<?php

namespace Modules\SystemCore\App\Models;

use App\Traits\UserActionsTrait;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\SystemCore\App\Enums\CustomerStatus;
use Modules\SystemCore\App\Enums\CustomerType;
use OwenIt\Auditing\Auditable;
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;

class CoreCustomer extends Model implements AuditableContract
{
    use Auditable, HasFactory, SoftDeletes, UserActionsTrait;

    protected $table = 'core_customers';

    protected $fillable = [
        'customer_code',
        'name',
        'company_name',
        'customer_type',
        'status',
        'email',
        'phone',
        'mobile',
        'website',
        'tax_id',
        'vat_number',
        'credit_limit',
        'payment_term_id',
        'currency_code',
        'latitude',
        'longitude',
        'notes',
        'tags',
        'metadata',
        'is_active',
        // CRM Fields
        'lifetime_value',
        'first_purchase_date',
        'last_purchase_date',
        'purchase_count',
        'average_order_value',
        'credit_used',
        'payment_terms',
        'discount_percentage',
        'tax_exempt',
        'preferred_payment_method',
        'preferred_delivery_method',
        'is_blacklisted',
        'blacklist_reason',
        'customer_group_id',
        'company_id',
        'created_by_id',
        'updated_by_id',
    ];

    protected function casts(): array
    {
        return [
            'customer_type' => CustomerType::class,
            'status' => CustomerStatus::class,
            'credit_limit' => 'decimal:2',
            'latitude' => 'float',
            'longitude' => 'float',
            'tags' => 'array',
            'metadata' => 'array',
            'is_active' => 'boolean',
            // CRM Field casts
            'lifetime_value' => 'decimal:2',
            'average_order_value' => 'decimal:2',
            'credit_used' => 'decimal:2',
            'discount_percentage' => 'decimal:2',
            'tax_exempt' => 'boolean',
            'is_blacklisted' => 'boolean',
            'first_purchase_date' => 'datetime',
            'last_purchase_date' => 'datetime',
            'purchase_count' => 'integer',
        ];
    }

    /**
     * Get all addresses for this customer
     */
    public function addresses(): HasMany
    {
        return $this->hasMany(CoreAddress::class, 'entity_id')
            ->where('entity_type', 'customer');
    }

    /**
     * Get primary address
     */
    public function primaryAddress(): HasOne
    {
        return $this->hasOne(CoreAddress::class, 'entity_id')
            ->where('entity_type', 'customer')
            ->where('is_primary', true);
    }

    /**
     * Get all contacts for this customer
     */
    public function contacts(): HasMany
    {
        return $this->hasMany(CoreContact::class, 'entity_id')
            ->where('entity_type', 'customer');
    }

    /**
     * Get primary contact
     */
    public function primaryContact(): HasOne
    {
        return $this->hasOne(CoreContact::class, 'entity_id')
            ->where('entity_type', 'customer')
            ->where('is_primary', true);
    }

    /**
     * Get payment term
     */
    public function paymentTerm(): BelongsTo
    {
        return $this->belongsTo(CorePaymentTerm::class, 'payment_term_id');
    }

    /**
     * Get sales orders
     */
    public function salesOrders(): HasMany
    {
        return $this->hasMany(CoreSalesOrder::class, 'customer_id');
    }

    /**
     * Get documents for this customer
     */
    public function documents(): HasMany
    {
        return $this->hasMany(CustomerDocument::class, 'customer_id');
    }

    /**
     * Scope for active customers
     */
    public function scopeActive($query)
    {
        return $query->where('is_active', true)
            ->where('status', CustomerStatus::Active);
    }

    /**
     * Scope by type
     */
    public function scopeByType($query, CustomerType $type)
    {
        return $query->where('customer_type', $type);
    }

    /**
     * Generate customer code using settings
     */
    public static function generateCustomerCode(): string
    {
        $settingsService = app(\App\Services\Settings\ModuleSettingsService::class);
        $prefix = $settingsService->get('SystemCore', 'customer_prefix', 'CUST');
        $padding = (int) $settingsService->get('SystemCore', 'customer_code_padding', 6);

        $lastCustomer = self::orderBy('id', 'desc')->first();
        $nextId = $lastCustomer ? $lastCustomer->id + 1 : 1;

        return $prefix.'-'.str_pad((string) $nextId, $padding, '0', STR_PAD_LEFT);
    }

    /**
     * Boot method
     */
    protected static function booted()
    {
        static::creating(function (CoreCustomer $customer) {
            if (! $customer->customer_code) {
                $customer->customer_code = self::generateCustomerCode();
            }
        });
    }

    // =====================================================
    // CRM Relationships
    // =====================================================

    /**
     * Get the customer group
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\Modules\CRMCore\App\Models\CustomerGroup, self>
     */
    public function customerGroup(): \Illuminate\Database\Eloquent\Relations\BelongsTo
    {
        return $this->belongsTo(\Modules\CRMCore\App\Models\CustomerGroup::class);
    }

    /**
     * Get the company (B2B relationship)
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\Modules\CRMCore\App\Models\Company, self>
     */
    public function company(): \Illuminate\Database\Eloquent\Relations\BelongsTo
    {
        return $this->belongsTo(\Modules\CRMCore\App\Models\Company::class);
    }

    /**
     * Get all deals for this customer
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany<\Modules\CRMCore\App\Models\Deal>
     */
    public function deals(): \Illuminate\Database\Eloquent\Relations\HasMany
    {
        return $this->hasMany(\Modules\CRMCore\App\Models\Deal::class, 'customer_id');
    }

    // =====================================================
    // CRM Business Logic Methods
    // =====================================================

    /**
     * Update customer statistics after a sale
     */
    public function recordPurchase(float $amount): void
    {
        $this->increment('purchase_count');
        $this->increment('lifetime_value', $amount);

        // Update average order value
        $this->average_order_value = $this->lifetime_value / $this->purchase_count;

        // Update first/last purchase dates
        if (! $this->first_purchase_date) {
            $this->first_purchase_date = now();
        }
        $this->last_purchase_date = now();

        $this->save();
    }

    /**
     * Check if customer has available credit
     */
    public function hasAvailableCredit(float $amount = 0): bool
    {
        $creditLimit = (float) ($this->credit_limit ?? 0);
        $creditUsed = (float) ($this->credit_used ?? 0);

        // Use bccomp for precise decimal comparison to avoid floating-point precision issues
        $availableCredit = bcsub((string) $creditLimit, (string) $creditUsed, 4);

        return bccomp($availableCredit, (string) $amount, 4) >= 0;
    }

    /**
     * Get available credit amount
     */
    public function getAvailableCreditAttribute(): float
    {
        $creditLimit = (float) ($this->credit_limit ?? 0);
        $creditUsed = (float) ($this->credit_used ?? 0);

        return max(0, $creditLimit - $creditUsed);
    }

    /**
     * Use credit
     */
    public function useCredit(float $amount): bool
    {
        if ($this->hasAvailableCredit($amount)) {
            $this->increment('credit_used', $amount);

            return true;
        }

        return false;
    }

    /**
     * Release credit (after payment)
     */
    public function releaseCredit(float $amount): void
    {
        $creditUsed = (float) ($this->credit_used ?? 0);
        $this->decrement('credit_used', min($amount, $creditUsed));
    }

    /**
     * Get customer segment based on purchase history
     */
    public function getSegment(): string
    {
        $lifetimeValue = (float) ($this->lifetime_value ?? 0);

        if ($lifetimeValue >= 100000) {
            return 'enterprise';
        } elseif ($lifetimeValue >= 50000) {
            return 'premium';
        } elseif ($lifetimeValue >= 10000) {
            return 'standard';
        }

        return 'basic';
    }

    /**
     * Check if customer is B2B (has a company)
     */
    public function isB2B(): bool
    {
        return $this->company_id !== null;
    }

    /**
     * Check if customer is B2C (individual without company)
     */
    public function isB2C(): bool
    {
        return ! $this->isB2B();
    }

    /**
     * Check if customer can make purchases
     */
    public function canPurchase(): bool
    {
        return $this->is_active && ! $this->is_blacklisted;
    }

    /**
     * Check if customer is eligible for tax exemption
     */
    public function isTaxExempt(): bool
    {
        return (bool) $this->tax_exempt;
    }

    /**
     * Check if customer has made a purchase
     */
    public function hasPurchased(): bool
    {
        return ($this->purchase_count ?? 0) > 0;
    }

    /**
     * Check if customer is new (first purchase within 30 days)
     */
    public function isNew(): bool
    {
        return $this->first_purchase_date &&
               $this->first_purchase_date->diffInDays(now()) <= 30;
    }

    /**
     * Check if customer is inactive (no purchase in last 90 days)
     */
    public function isInactive(): bool
    {
        return $this->last_purchase_date &&
               $this->last_purchase_date->diffInDays(now()) > 90;
    }

    /**
     * Get customer display name
     */
    public function getDisplayNameAttribute(): string
    {
        return $this->name ?? 'Unknown Customer';
    }

    /**
     * Get customer classification
     */
    public function getClassification(): string
    {
        if ($this->customerGroup) {
            return $this->customerGroup->name;
        }

        // Default classification based on type and segment
        $type = $this->isB2B() ? 'B2B' : 'B2C';
        $segment = $this->getSegment();

        return "{$type} - {$segment}";
    }

    /**
     * Get customer risk level based on credit and payment history
     */
    public function getRiskLevel(): string
    {
        // Check if blacklisted
        if ($this->is_blacklisted) {
            return 'high';
        }

        // Check credit utilization
        $creditLimit = (float) ($this->credit_limit ?? 0);
        $creditUsed = (float) ($this->credit_used ?? 0);
        $creditUtilization = $creditLimit > 0
            ? ($creditUsed / $creditLimit) * 100
            : 0;

        if ($creditUtilization > 80) {
            return 'medium';
        }

        // Check if inactive
        if ($this->isInactive()) {
            return 'medium';
        }

        return 'low';
    }

    /**
     * Get the billing entity for this customer
     * Returns Company for B2B (requires CRMCore module), self for B2C
     */
    public function getBillingEntity(): \Modules\CRMCore\App\Models\Company|self
    {
        if (moduleExists('CRMCore') && $this->isB2B() && $this->company) {
            return $this->company;
        }

        return $this;
    }

    /**
     * Scope for non-blacklisted customers
     *
     * @param  \Illuminate\Database\Eloquent\Builder<self>  $query
     * @return \Illuminate\Database\Eloquent\Builder<self>
     */
    public function scopeNotBlacklisted($query): \Illuminate\Database\Eloquent\Builder
    {
        return $query->where('is_blacklisted', false);
    }

    /**
     * Scope for VIP customers (high lifetime value)
     *
     * @param  \Illuminate\Database\Eloquent\Builder<self>  $query
     * @return \Illuminate\Database\Eloquent\Builder<self>
     */
    public function scopeVip($query): \Illuminate\Database\Eloquent\Builder
    {
        return $query->where('lifetime_value', '>=', 50000);
    }

    /**
     * Create customer from first purchase (for walk-in or new customers)
     *
     * @param  array<string, mixed>  $customerData
     * @param  array<string, mixed>  $purchaseData
     */
    public static function createFromFirstPurchase(array $customerData, array $purchaseData = []): self
    {
        $customer = self::create(array_merge([
            'lifetime_value' => 0,
            'purchase_count' => 0,
            'average_order_value' => 0,
            'credit_limit' => 1000,
            'credit_used' => 0,
            'payment_terms' => 'cod',
            'discount_percentage' => 0,
            'tax_exempt' => false,
            'is_active' => true,
            'is_blacklisted' => false,
            'first_purchase_date' => now(),
        ], $customerData));

        // Update purchase statistics if provided
        if (isset($purchaseData['amount'])) {
            $customer->recordPurchase((float) $purchaseData['amount']);
        }

        return $customer;
    }
}
