<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;
use Morilog\Jalali\Jalalian;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Traits\LogsActivity;

class Invoice extends Model
{
    use LogsActivity;

    protected $fillable = [
        'number', 'serial_number', 'tax_id', 'contract_number',
        'type', 'customer_id', 'company_id', 'bank_account_id', 'user_id', 'status',
        'issue_date', 'due_date', 'subtotal', 'discount_total', 'shipping_cost',
        'tax_percent', 'vat_enabled', 'layout', 'sale_terms', 'delivery_place', 'warranty', 'attachment',
        'tax_amount', 'grand_total', 'paid_amount',
        'balance', 'notes', 'share_token', 'converted_from_id',
    ];

    protected $casts = [
        'issue_date' => 'date',
        'due_date' => 'date',
        'subtotal' => 'decimal:2',
        'discount_total' => 'decimal:2',
        'shipping_cost' => 'decimal:2',
        'tax_percent' => 'decimal:2',
        'vat_enabled' => 'boolean',
        'tax_amount' => 'decimal:2',
        'grand_total' => 'decimal:2',
        'paid_amount' => 'decimal:2',
        'balance' => 'decimal:2',
    ];

    protected static function booted(): void
    {
        static::creating(function (Invoice $invoice) {
            if (empty($invoice->number)) {
                $invoice->number = static::generateNumber($invoice->type);
            }
        });

        // اطلاع‌رسانی صدور فاکتور به مدیران
        static::created(function (Invoice $invoice) {
            if ($invoice->status === 'draft') {
                return;
            }
            $typeLabel = ['proforma' => 'پیش‌فاکتور', 'invoice' => 'فاکتور', 'official' => 'فاکتور رسمی'][$invoice->type] ?? 'فاکتور';
            $amount = \App\Support\NumberToWords::money($invoice->grand_total) . ' ریال';
            \App\Support\Notifier::toManagers(
                "{$typeLabel} جدید صادر شد",
                "{$typeLabel} {$invoice->number} به مبلغ {$amount} برای {$invoice->customer?->display_name} صادر شد.",
                url('/admin/invoices/' . $invoice->id . '/edit'),
                icon: 'heroicon-o-document-text',
                color: 'info',
            );
        });
    }

    public function getActivitylogOptions(): LogOptions
    {
        return LogOptions::defaults()
            ->logOnly(['number', 'type', 'status', 'grand_total', 'paid_amount'])
            ->logOnlyDirty();
    }

    /* ---------------------- روابط ---------------------- */

    public function customer(): BelongsTo
    {
        return $this->belongsTo(Customer::class);
    }

    public function company(): BelongsTo
    {
        return $this->belongsTo(Company::class);
    }

    public function bankAccount(): BelongsTo
    {
        return $this->belongsTo(BankAccount::class);
    }

    public function getAmountInWordsAttribute(): string
    {
        return \App\Support\NumberToWords::rials($this->grand_total);
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function items(): HasMany
    {
        return $this->hasMany(InvoiceItem::class)->orderBy('sort');
    }

    public function payments(): HasMany
    {
        return $this->hasMany(Payment::class)->latest('paid_at');
    }

    public function tasks(): HasMany
    {
        return $this->hasMany(Task::class);
    }

    public function convertedFrom(): BelongsTo
    {
        return $this->belongsTo(Invoice::class, 'converted_from_id');
    }

    /* ---------------------- شماره‌گذاری ---------------------- */

    public static function generateNumber(string $type = 'proforma'): string
    {
        $setting = Setting::current();
        $prefix = $type === 'proforma'
            ? 'PRO'
            : ($setting->invoice_prefix ?: 'INV');

        $jalaliYear = Jalalian::now()->getYear();

        $last = static::where('number', 'like', "{$prefix}-{$jalaliYear}-%")
            ->orderByDesc('id')
            ->value('number');

        $seq = 1;
        if ($last && preg_match('/-(\d+)$/', $last, $m)) {
            $seq = (int) $m[1] + 1;
        }

        return sprintf('%s-%s-%03d', $prefix, $jalaliYear, $seq);
    }

    /* ---------------------- محاسبات ---------------------- */

    /**
     * بازمحاسبه‌ی کامل مبالغ بر اساس ردیف‌ها و پرداخت‌ها.
     */
    public function recalculate(bool $save = true): self
    {
        $subtotal = 0;
        foreach ($this->items as $item) {
            $line = ($item->quantity * $item->unit_price) - $item->discount;
            if ($item->line_total != $line) {
                $item->line_total = $line;
                $item->saveQuietly();
            }
            $subtotal += $line;
        }

        $this->subtotal = $subtotal;
        $taxBase = max(0, $subtotal - $this->discount_total);
        // مالیات بر ارزش افزوده فقط در صورت فعال‌بودن
        $this->tax_amount = $this->vat_enabled
            ? round($taxBase * ($this->tax_percent / 100), 2)
            : 0;
        // مبلغ نهایی = (جمع - تخفیف) + مالیات + حمل و نقل
        $this->grand_total = $taxBase + $this->tax_amount + (float) $this->shipping_cost;

        $this->paid_amount = (float) $this->payments()->sum('amount');
        $this->balance = $this->grand_total - $this->paid_amount;

        $this->syncPaymentStatus();

        if ($save) {
            $this->saveQuietly();
        }

        return $this;
    }

    /**
     * به‌روزرسانی خودکار وضعیت بر اساس مبلغ پرداختی.
     */
    public function syncPaymentStatus(): void
    {
        if (in_array($this->status, ['void', 'draft'])) {
            return;
        }

        if ($this->paid_amount <= 0) {
            $this->status = 'issued';
        } elseif ($this->paid_amount < $this->grand_total) {
            $this->status = 'partial';
        } else {
            $this->status = 'paid';
        }
    }

    /**
     * تبدیل پیش‌فاکتور به فاکتور رسمی.
     */
    public function convertToInvoice(): self
    {
        if ($this->type === 'invoice') {
            return $this;
        }

        $invoice = $this->replicate(['number', 'share_token']);
        $invoice->type = 'invoice';
        $invoice->status = 'issued';
        $invoice->number = static::generateNumber('invoice');
        $invoice->converted_from_id = $this->id;
        $invoice->issue_date = now();
        $invoice->paid_amount = 0;
        $invoice->save();

        foreach ($this->items as $item) {
            $copy = $item->replicate(['invoice_id']);
            $copy->invoice_id = $invoice->id;
            $copy->save();
        }

        $invoice->recalculate();

        return $invoice;
    }

    /**
     * کپی/تکرار فاکتور.
     */
    public function duplicate(): self
    {
        $copy = $this->replicate(['number', 'share_token', 'paid_amount', 'balance', 'converted_from_id']);
        $copy->status = 'draft';
        $copy->number = static::generateNumber($this->type);
        $copy->issue_date = now();
        $copy->paid_amount = 0;
        $copy->save();

        foreach ($this->items as $item) {
            $newItem = $item->replicate(['invoice_id']);
            $newItem->invoice_id = $copy->id;
            $newItem->save();
        }

        $copy->recalculate();

        return $copy;
    }

    public function ensureShareToken(): string
    {
        if (! $this->share_token) {
            $this->share_token = Str::random(40);
            $this->saveQuietly();
        }

        return $this->share_token;
    }

    /* ---------------------- Scope دسترسی ---------------------- */

    public function scopeForUser(Builder $query, User $user): Builder
    {
        if ($user->canSeeAll('invoices')) {
            return $query;
        }

        return $query->where('user_id', $user->id);
    }
}
