<?php

namespace Tests\Traits;

use Modules\SystemCore\App\Enums\CustomerStatus;
use Modules\SystemCore\App\Enums\CustomerType;
use Modules\SystemCore\App\Enums\OrderStatus;
use Modules\SystemCore\App\Enums\ProductStatus;
use Modules\SystemCore\App\Enums\SupplierStatus;
use Modules\SystemCore\App\Models\CoreAddress;
use Modules\SystemCore\App\Models\CoreContact;
use Modules\SystemCore\App\Models\CoreCustomer;
use Modules\SystemCore\App\Models\CorePaymentTerm;
use Modules\SystemCore\App\Models\CorePricingRule;
use Modules\SystemCore\App\Models\CoreProduct;
use Modules\SystemCore\App\Models\CoreProductCategory;
use Modules\SystemCore\App\Models\CoreProductVariant;
use Modules\SystemCore\App\Models\CorePurchaseOrder;
use Modules\SystemCore\App\Models\CorePurchaseOrderLine;
use Modules\SystemCore\App\Models\CoreSalesOrder;
use Modules\SystemCore\App\Models\CoreSalesOrderLine;
use Modules\SystemCore\App\Models\CoreSupplier;
use Modules\SystemCore\App\Models\CoreTaxConfiguration;
use Modules\SystemCore\App\Models\CustomerDocument;
use Modules\SystemCore\App\Models\PostingLog;
use Modules\SystemCore\App\Models\SupplierDocument;

/**
 * Helper trait for creating SystemCore test entities.
 */
trait CreatesSystemCoreEntities
{
    /**
     * Create and return an active customer.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCoreCustomer(array $attributes = []): CoreCustomer
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        return CoreCustomer::create(array_merge([
            'name' => 'Test Customer '.uniqid(),
            'email' => 'customer'.uniqid().'@example.com',
            'customer_type' => CustomerType::B2B,
            'status' => CustomerStatus::Active,
            'is_active' => true,
            'credit_limit' => 10000.00,
            'credit_used' => 0,
            'lifetime_value' => 0,
            'purchase_count' => 0,
            'average_order_value' => 0,
            'is_blacklisted' => false,
            'created_by_id' => $userId,
        ], $attributes));
    }

    /**
     * Create a B2B customer (with company association).
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createB2BCustomer(array $attributes = []): CoreCustomer
    {
        return $this->createCoreCustomer(array_merge([
            'customer_type' => CustomerType::B2B,
            'company_name' => 'Test Company '.uniqid(),
        ], $attributes));
    }

    /**
     * Create a B2C customer (individual).
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createB2CCustomer(array $attributes = []): CoreCustomer
    {
        return $this->createCoreCustomer(array_merge([
            'customer_type' => CustomerType::B2C,
            'company_id' => null,
            'company_name' => null,
        ], $attributes));
    }

    /**
     * Create an inactive customer.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createInactiveCustomer(array $attributes = []): CoreCustomer
    {
        return $this->createCoreCustomer(array_merge([
            'status' => CustomerStatus::Inactive,
            'is_active' => false,
        ], $attributes));
    }

    /**
     * Create a blacklisted customer.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createBlacklistedCustomer(array $attributes = []): CoreCustomer
    {
        return $this->createCoreCustomer(array_merge([
            'is_blacklisted' => true,
            'blacklist_reason' => 'Payment default',
        ], $attributes));
    }

    /**
     * Create a VIP customer (high lifetime value).
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createVipCustomer(array $attributes = []): CoreCustomer
    {
        return $this->createCoreCustomer(array_merge([
            'lifetime_value' => 75000,
            'purchase_count' => 50,
            'average_order_value' => 1500,
            'first_purchase_date' => now()->subYear(),
            'last_purchase_date' => now()->subDays(5),
        ], $attributes));
    }

    /**
     * Create and return an active supplier.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCoreSupplier(array $attributes = []): CoreSupplier
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        return CoreSupplier::create(array_merge([
            'name' => 'Test Supplier '.uniqid(),
            'email' => 'supplier'.uniqid().'@example.com',
            'status' => SupplierStatus::Active,
            'is_active' => true,
            'lead_time_days' => 7,
            'created_by_id' => $userId,
        ], $attributes));
    }

    /**
     * Create an inactive supplier.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createInactiveSupplier(array $attributes = []): CoreSupplier
    {
        return $this->createCoreSupplier(array_merge([
            'status' => SupplierStatus::Inactive,
            'is_active' => false,
        ], $attributes));
    }

    /**
     * Create and return a product category.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCoreProductCategory(array $attributes = []): CoreProductCategory
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        return CoreProductCategory::create(array_merge([
            'name' => 'Category '.uniqid(),
            'code' => 'CAT'.strtoupper(uniqid()),
            'is_active' => true,
            'display_order' => 1,
            'created_by_id' => $userId,
        ], $attributes));
    }

    /**
     * Create and return an active product.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCoreProduct(array $attributes = []): CoreProduct
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        // Create category if not provided
        if (! isset($attributes['category_id'])) {
            $category = $this->createCoreProductCategory(['created_by_id' => $userId]);
            $attributes['category_id'] = $category->id;
        }

        return CoreProduct::create(array_merge([
            'name' => 'Product '.uniqid(),
            'sku' => 'SKU'.strtoupper(uniqid()),
            'status' => ProductStatus::Active,
            'is_active' => true,
            'selling_price' => 99.99,
            'cost_price' => 49.99,
            'base_price' => 89.99,
            'is_trackable' => true,
            'has_variants' => false,
            'created_by_id' => $userId,
        ], $attributes));
    }

    /**
     * Create an inactive product.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createInactiveProduct(array $attributes = []): CoreProduct
    {
        return $this->createCoreProduct(array_merge([
            'status' => ProductStatus::Inactive,
            'is_active' => false,
        ], $attributes));
    }

    /**
     * Create and return a sales order.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCoreSalesOrder(array $attributes = []): CoreSalesOrder
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        // Create customer if not provided
        if (! isset($attributes['customer_id'])) {
            $customer = $this->createCoreCustomer(['created_by_id' => $userId]);
            $attributes['customer_id'] = $customer->id;
        }

        return CoreSalesOrder::create(array_merge([
            'order_date' => now(),
            'status' => OrderStatus::Pending,
            'subtotal' => 1000.00,
            'tax_amount' => 50.00,
            'discount_amount' => 0,
            'shipping_cost' => 10.00,
            'total_amount' => 1060.00,
            'payment_status' => 'pending',
            'paid_amount' => 0,
            'fulfillment_status' => 'pending',
            'user_id' => $userId,
            'created_by_id' => $userId,
        ], $attributes));
    }

    /**
     * Create a paid sales order.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createPaidSalesOrder(array $attributes = []): CoreSalesOrder
    {
        $totalAmount = $attributes['total_amount'] ?? 1060.00;

        return $this->createCoreSalesOrder(array_merge([
            'status' => OrderStatus::Confirmed,
            'payment_status' => 'paid',
            'paid_amount' => $totalAmount,
        ], $attributes));
    }

    /**
     * Create a completed sales order.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCompletedSalesOrder(array $attributes = []): CoreSalesOrder
    {
        $totalAmount = $attributes['total_amount'] ?? 1060.00;

        return $this->createCoreSalesOrder(array_merge([
            'status' => OrderStatus::Completed,
            'payment_status' => 'paid',
            'paid_amount' => $totalAmount,
            'fulfillment_status' => 'fulfilled',
            'fulfilled_at' => now(),
        ], $attributes));
    }

    /**
     * Create and return a purchase order.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCorePurchaseOrder(array $attributes = []): CorePurchaseOrder
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        // Create supplier if not provided
        if (! isset($attributes['supplier_id'])) {
            $supplier = $this->createCoreSupplier(['created_by_id' => $userId]);
            $attributes['supplier_id'] = $supplier->id;
        }

        return CorePurchaseOrder::create(array_merge([
            'order_date' => now(),
            'status' => OrderStatus::Pending,
            'subtotal' => 500.00,
            'tax_amount' => 25.00,
            'discount_amount' => 0,
            'shipping_cost' => 5.00,
            'total_amount' => 530.00,
            'payment_status' => 'pending',
            'paid_amount' => 0,
            'user_id' => $userId,
            'created_by_id' => $userId,
        ], $attributes));
    }

    /**
     * Create a paid purchase order.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createPaidPurchaseOrder(array $attributes = []): CorePurchaseOrder
    {
        $totalAmount = $attributes['total_amount'] ?? 530.00;

        return $this->createCorePurchaseOrder(array_merge([
            'status' => OrderStatus::Confirmed,
            'payment_status' => 'paid',
            'paid_amount' => $totalAmount,
        ], $attributes));
    }

    /**
     * Create and return a payment term.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCorePaymentTerm(array $attributes = []): CorePaymentTerm
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        return CorePaymentTerm::create(array_merge([
            'name' => 'Net 30',
            'code' => 'NET30'.uniqid(),
            'days' => 30,
            'is_active' => true,
            'created_by_id' => $userId,
        ], $attributes));
    }

    /**
     * Create and return a tax configuration.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCoreTaxConfiguration(array $attributes = []): CoreTaxConfiguration
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        return CoreTaxConfiguration::create(array_merge([
            'name' => 'Standard VAT',
            'code' => 'VAT'.uniqid(),
            'rate' => 5.0,
            'type' => 'percentage',
            'is_active' => true,
            'is_default' => false,
            'created_by_id' => $userId,
        ], $attributes));
    }

    /**
     * Create a default tax configuration.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createDefaultTaxConfiguration(array $attributes = []): CoreTaxConfiguration
    {
        return $this->createCoreTaxConfiguration(array_merge([
            'is_default' => true,
        ], $attributes));
    }

    /**
     * Get or create a default product category.
     */
    protected function getOrCreateDefaultCategory(): CoreProductCategory
    {
        return CoreProductCategory::firstOrCreate(
            ['code' => 'DEFAULT'],
            [
                'name' => 'Default Category',
                'is_active' => true,
                'created_by_id' => auth()->id() ?? 1,
            ]
        );
    }

    /**
     * Get or create a default payment term (Net 30).
     */
    protected function getOrCreateDefaultPaymentTerm(): CorePaymentTerm
    {
        return CorePaymentTerm::firstOrCreate(
            ['code' => 'NET30'],
            [
                'name' => 'Net 30',
                'days' => 30,
                'is_active' => true,
                'created_by_id' => auth()->id() ?? 1,
            ]
        );
    }

    // ==========================================
    // Address & Contact Helpers
    // ==========================================

    /**
     * Create and return a core address.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCoreAddress(array $attributes = []): CoreAddress
    {
        return CoreAddress::create(array_merge([
            'entity_type' => $attributes['entity_type'] ?? 'customer',
            'entity_id' => $attributes['entity_id'] ?? 1,
            'address_type' => 'billing',
            'address_line_1' => '123 Test Street',
            'city' => 'Test City',
            'state' => 'Test State',
            'country' => 'US',
            'postal_code' => '12345',
            'is_primary' => true,
            'is_billing' => true,
            'is_shipping' => false,
        ], $attributes));
    }

    /**
     * Create and return a core contact.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCoreContact(array $attributes = []): CoreContact
    {
        return CoreContact::create(array_merge([
            'entity_type' => $attributes['entity_type'] ?? 'customer',
            'entity_id' => $attributes['entity_id'] ?? 1,
            'contact_type' => 'primary',
            'first_name' => 'John',
            'last_name' => 'Doe',
            'email' => 'contact'.uniqid().'@example.com',
            'phone' => '+1234567890',
            'is_primary' => true,
        ], $attributes));
    }

    // ==========================================
    // Document Helpers
    // ==========================================

    /**
     * Create and return a customer document.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCustomerDocument(array $attributes = []): CustomerDocument
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        // Create customer if not provided
        if (! isset($attributes['customer_id'])) {
            $customer = $this->createCoreCustomer(['created_by_id' => $userId]);
            $attributes['customer_id'] = $customer->id;
        }

        return CustomerDocument::create(array_merge([
            'document_title' => 'Test Document '.uniqid(),
            'document_number' => 'DOC'.strtoupper(uniqid()),
            'document_type' => 'contract',
            'file_path' => 'documents/test-file.pdf',
            'file_name' => 'test-file.pdf',
            'mime_type' => 'application/pdf',
            'file_size' => 1024,
            'issue_date' => now()->subMonth(),
            'expiry_date' => now()->addYear(),
            'is_active' => true,
        ], $attributes));
    }

    /**
     * Create an expired customer document.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createExpiredCustomerDocument(array $attributes = []): CustomerDocument
    {
        return $this->createCustomerDocument(array_merge([
            'expiry_date' => now()->subDays(10),
        ], $attributes));
    }

    /**
     * Create a customer document that is about to expire.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createAboutToExpireCustomerDocument(int $days = 15, array $attributes = []): CustomerDocument
    {
        return $this->createCustomerDocument(array_merge([
            'expiry_date' => now()->addDays($days),
        ], $attributes));
    }

    /**
     * Create and return a supplier document.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createSupplierDocument(array $attributes = []): SupplierDocument
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        // Create supplier if not provided
        if (! isset($attributes['supplier_id'])) {
            $supplier = $this->createCoreSupplier(['created_by_id' => $userId]);
            $attributes['supplier_id'] = $supplier->id;
        }

        return SupplierDocument::create(array_merge([
            'document_title' => 'Supplier Document '.uniqid(),
            'document_number' => 'SDOC'.strtoupper(uniqid()),
            'document_type' => 'license',
            'file_path' => 'documents/supplier-doc.pdf',
            'file_name' => 'supplier-doc.pdf',
            'mime_type' => 'application/pdf',
            'file_size' => 2048,
            'issue_date' => now()->subMonth(),
            'expiry_date' => now()->addYear(),
            'is_active' => true,
        ], $attributes));
    }

    // ==========================================
    // Order Line Helpers
    // ==========================================

    /**
     * Create and return a sales order line.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCoreSalesOrderLine(array $attributes = []): CoreSalesOrderLine
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        // Create sales order if not provided
        if (! isset($attributes['sales_order_id'])) {
            $order = $this->createCoreSalesOrder(['created_by_id' => $userId]);
            $attributes['sales_order_id'] = $order->id;
        }

        // Create product if not provided
        if (! isset($attributes['product_id'])) {
            $product = $this->createCoreProduct(['created_by_id' => $userId]);
            $attributes['product_id'] = $product->id;
            $attributes['product_name'] = $attributes['product_name'] ?? $product->name;
            $attributes['product_sku'] = $attributes['product_sku'] ?? $product->sku;
        }

        return CoreSalesOrderLine::create(array_merge([
            'quantity' => 2,
            'unit_price' => 99.99,
            'unit_cost' => 49.99,
            'tax_rate' => 5.00,
            'tax_amount' => 10.00,
            'discount_rate' => 0,
            'discount_amount' => 0,
            'subtotal' => 199.98,
            'line_total' => 209.98,
            'profit' => 100.00,
            'fulfilled_quantity' => 0,
            'is_fulfilled' => false,
            'created_by_id' => $userId,
        ], $attributes));
    }

    /**
     * Create a fulfilled sales order line.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createFulfilledSalesOrderLine(array $attributes = []): CoreSalesOrderLine
    {
        $quantity = $attributes['quantity'] ?? 2;

        return $this->createCoreSalesOrderLine(array_merge([
            'fulfilled_quantity' => $quantity,
            'is_fulfilled' => true,
        ], $attributes));
    }

    /**
     * Create and return a purchase order line.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCorePurchaseOrderLine(array $attributes = []): CorePurchaseOrderLine
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        // Create purchase order if not provided
        if (! isset($attributes['purchase_order_id'])) {
            $order = $this->createCorePurchaseOrder(['created_by_id' => $userId]);
            $attributes['purchase_order_id'] = $order->id;
        }

        // Create product if not provided
        if (! isset($attributes['product_id'])) {
            $product = $this->createCoreProduct(['created_by_id' => $userId]);
            $attributes['product_id'] = $product->id;
            $attributes['product_name'] = $attributes['product_name'] ?? $product->name;
            $attributes['product_sku'] = $attributes['product_sku'] ?? $product->sku;
        }

        return CorePurchaseOrderLine::create(array_merge([
            'quantity' => 10,
            'unit_price' => 25.00,
            'tax_rate' => 5.00,
            'tax_amount' => 12.50,
            'discount_rate' => 0,
            'discount_amount' => 0,
            'subtotal' => 250.00,
            'line_total' => 262.50,
            'received_quantity' => 0,
            'is_received' => false,
            'created_by_id' => $userId,
        ], $attributes));
    }

    // ==========================================
    // Product Variant & Pricing Rule Helpers
    // ==========================================

    /**
     * Create and return a product variant.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCoreProductVariant(array $attributes = []): CoreProductVariant
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        // Create product if not provided
        if (! isset($attributes['product_id'])) {
            $product = $this->createCoreProduct([
                'has_variants' => true,
                'created_by_id' => $userId,
            ]);
            $attributes['product_id'] = $product->id;
        }

        return CoreProductVariant::create(array_merge([
            'sku' => 'VAR'.strtoupper(uniqid()),
            'name' => 'Variant '.uniqid(),
            'attributes' => ['color' => 'Red', 'size' => 'Large'],
            'price' => 109.99,
            'cost_price' => 54.99,
            'stock' => 100,
            'is_active' => true,
        ], $attributes));
    }

    /**
     * Create and return a pricing rule.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createCorePricingRule(array $attributes = []): CorePricingRule
    {
        $userId = $attributes['created_by_id'] ?? auth()->id() ?? 1;

        // Create product if not provided
        if (! isset($attributes['product_id'])) {
            $product = $this->createCoreProduct(['created_by_id' => $userId]);
            $attributes['product_id'] = $product->id;
        }

        return CorePricingRule::create(array_merge([
            'min_quantity' => 1,
            'max_quantity' => 100,
            'price' => 89.99,
            'discount_percentage' => 10.00,
            'valid_from' => now()->subMonth(),
            'valid_until' => now()->addMonth(),
            'is_active' => true,
        ], $attributes));
    }

    /**
     * Create an inactive pricing rule.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createInactivePricingRule(array $attributes = []): CorePricingRule
    {
        return $this->createCorePricingRule(array_merge([
            'is_active' => false,
        ], $attributes));
    }

    /**
     * Create an expired pricing rule.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createExpiredPricingRule(array $attributes = []): CorePricingRule
    {
        return $this->createCorePricingRule(array_merge([
            'valid_from' => now()->subMonths(3),
            'valid_until' => now()->subMonth(),
        ], $attributes));
    }

    // ==========================================
    // Posting Log Helpers
    // ==========================================

    /**
     * Create and return a posting log.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createPostingLog(array $attributes = []): PostingLog
    {
        $userId = $attributes['posted_by'] ?? auth()->id() ?? 1;

        return PostingLog::create(array_merge([
            'source_module' => 'SystemCore',
            'source_entity_type' => 'sales_order',
            'source_entity_id' => 1,
            'target_module' => 'AccountingCore',
            'target_entity_type' => 'transaction',
            'target_entity_id' => 1,
            'action' => 'create',
            'status' => 'success',
            'description' => 'Test posting log',
            'amount' => 1000.00,
            'posted_by' => $userId,
            'posted_at' => now(),
        ], $attributes));
    }

    /**
     * Create a failed posting log.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createFailedPostingLog(array $attributes = []): PostingLog
    {
        return $this->createPostingLog(array_merge([
            'status' => 'failed',
            'target_entity_id' => null,
            'error_message' => 'Test error message',
            'retry_count' => 0,
        ], $attributes));
    }

    /**
     * Create a pending posting log.
     *
     * @param  array<string, mixed>  $attributes
     */
    protected function createPendingPostingLog(array $attributes = []): PostingLog
    {
        return $this->createPostingLog(array_merge([
            'status' => 'pending',
            'target_entity_id' => null,
        ], $attributes));
    }
}
