<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Party extends Model
{
    use HasFactory, SoftDeletes;

    protected $fillable = [
        'code',
        'name',
        'type',
        'account_id',
        'contact_person',
        'phone',
        'mobile',
        'email',
        'address',
        'city',
        'state',
        'country',
        'postal_code',
        'ntn',
        'strn',
        'credit_limit',
        'credit_days',
        'opening_balance',
        'opening_type',
        'current_balance',
        'notes',
        'is_active',
    ];

    protected $casts = [
        'credit_limit' => 'decimal:2',
        'opening_balance' => 'decimal:2',
        'current_balance' => 'decimal:2',
        'is_active' => 'boolean',
    ];

    /**
     * Linked account relationship
     */
    public function account(): BelongsTo
    {
        return $this->belongsTo(Account::class);
    }

    /**
     * Purchases relationship (for suppliers)
     */
    public function purchases(): HasMany
    {
        return $this->hasMany(Purchase::class);
    }

    /**
     * Sales relationship (for customers)
     */
    public function sales(): HasMany
    {
        return $this->hasMany(Sale::class);
    }

    /**
     * Contracts relationship
     */
    public function contracts(): HasMany
    {
        return $this->hasMany(Contract::class);
    }

    /**
     * Active contracts relationship
     */
    public function activeContracts(): HasMany
    {
        return $this->hasMany(Contract::class)->where('status', 'active');
    }

    /**
     * Transactions relationship
     */
    public function transactions(): HasMany
    {
        return $this->hasMany(Transaction::class);
    }

    /**
     * Get balance status (Receivable/Payable/Advance)
     */
    public function getBalanceStatusAttribute(): string
    {
        if ($this->current_balance > 0) {
            return $this->type === 'supplier' ? 'Payable' : 'Receivable';
        } elseif ($this->current_balance < 0) {
            return 'Advance';
        }
        return 'Settled';
    }

    /**
     * Get formatted balance
     */
    public function getFormattedBalanceAttribute(): string
    {
        return 'Rs. ' . number_format(abs($this->current_balance), 2);
    }

    /**
     * Update balance from transactions
     */
    public function updateBalance(): void
    {
        $debit = $this->transactions()->sum('debit');
        $credit = $this->transactions()->sum('credit');
        
        // For customers: Receivable = Debit - Credit (positive means they owe us)
        // For suppliers: Payable = Credit - Debit (positive means we owe them)
        if ($this->type === 'customer') {
            $this->current_balance = $this->opening_balance + $debit - $credit;
        } else {
            $this->current_balance = $this->opening_balance + $credit - $debit;
        }
        
        $this->save();
    }

    /**
     * Scope for active parties
     */
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    /**
     * Scope for customers
     */
    public function scopeCustomers($query)
    {
        return $query->whereIn('type', ['customer', 'both']);
    }

    /**
     * Scope for suppliers
     */
    public function scopeSuppliers($query)
    {
        return $query->whereIn('type', ['supplier', 'both']);
    }

    /**
     * Scope with outstanding balance
     */
    public function scopeWithBalance($query)
    {
        return $query->where('current_balance', '!=', 0);
    }

    /**
     * Generate next party code
     */
    public static function generateCode(string $type): string
    {
        $prefix = $type === 'customer' ? 'C' : 'S';
        $lastParty = self::where('code', 'like', $prefix . '%')
            ->orderBy('code', 'desc')
            ->first();

        if ($lastParty) {
            $lastNumber = intval(substr($lastParty->code, 1));
            return $prefix . str_pad($lastNumber + 1, 4, '0', STR_PAD_LEFT);
        }

        return $prefix . '0001';
    }

    /**
     * Boot method to auto-create linked account
     */
    protected static function boot()
    {
        parent::boot();

        static::creating(function ($party) {
            // Generate code if not provided
            if (empty($party->code)) {
                $party->code = self::generateCode($party->type);
            }

            // Create linked account in Chart of Accounts
            if (!$party->account_id) {
                $accountType = $party->type === 'customer' ? 'asset' : 'liability';
                $subType = $party->type === 'customer' ? 'receivable' : 'payable';
                
                $account = Account::create([
                    'code' => Account::generateCode($accountType),
                    'name' => $party->name,
                    'type' => $accountType,
                    'sub_type' => $subType,
                    'opening_balance' => $party->opening_balance,
                    'opening_type' => $party->opening_type,
                    'current_balance' => $party->opening_balance,
                    'is_system' => true,
                ]);
                
                $party->account_id = $account->id;
            }

            // Set initial balance
            $party->current_balance = $party->opening_balance;
        });
    }
}
