<?php

namespace App\Models;

use App\Helpers\DebitNoteDocumentSettings;
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;

class DebitNote extends Model
{
    protected $fillable = [
        'company_id', 'entity_type', 'customer_id', 'vendor_id',
        'invoice_id', 'purchase_bill_id',
        'debit_note_number', 'debit_note_prefix', 'debit_note_seq',
        'debit_note_date', 'related_document_number', 'related_document_date',
        'reason', 'status',
        'place_of_supply', 'is_igst', 'tax_on',
        'subtotal', 'taxable_amount', 'discount_amount',
        'shipping_charges', 'discount_on_total', 'discount_all_percent',
        'discount_all_type', 'discount_all_value', 'custom_amount', 'custom_amount_label',
        'advance_payment', 'has_shipping', 'has_discount_total', 'has_discount_all',
        'has_custom_amount', 'has_advance_payment', 'has_total_quantity',
        'total_quantity_unit', 'total_quantity', 'show_cess', 'shipping_mode',
        'total_tax', 'cgst_amount', 'sgst_amount', 'igst_amount',
        'round_off', 'grand_total', 'amount_due', 'paid_amount',
        'notes', 'terms', 'private_notes', 'share_token',
    ];

    protected $casts = [
        'debit_note_date' => 'date',
        'related_document_date' => 'date',
        'grand_total' => 'decimal:2',
        'amount_due' => 'decimal:2',
        'paid_amount' => 'decimal:2',
        'round_off' => 'decimal:2',
        'total_tax' => 'decimal:2',
        'total_quantity' => 'decimal:3',
        'has_shipping' => 'boolean',
        'has_discount_total' => 'boolean',
        'has_discount_all' => 'boolean',
        'has_custom_amount' => 'boolean',
        'has_advance_payment' => 'boolean',
        'has_total_quantity' => 'boolean',
        'show_cess' => 'boolean',
        'is_igst' => 'boolean',
    ];

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

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

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

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

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

    public function isClient(): bool
    {
        return $this->entity_type === 'client';
    }

    public function party(): Customer|Vendor|null
    {
        return $this->isClient() ? $this->customer : $this->vendor;
    }

    public function partyName(): string
    {
        return $this->party()?->name ?? '—';
    }

    public function statusMeta(): array
    {
        return config('debit_note.statuses.'.$this->status, config('debit_note.statuses.draft'));
    }

    public function reasonLabel(): string
    {
        return config('debit_note.reasons.'.$this->reason, $this->reason);
    }

    public function displayDocumentNumber(): ?string
    {
        if ($this->isClient() && $this->invoice_id && $this->relationLoaded('invoice') && $this->invoice) {
            return $this->invoice->invoice_number;
        }

        if (! $this->isClient() && $this->purchase_bill_id && $this->relationLoaded('purchaseBill') && $this->purchaseBill) {
            return $this->purchaseBill->bill_number;
        }

        return $this->related_document_number;
    }

    public function displayDocumentDate(): ?\Illuminate\Support\Carbon
    {
        if ($this->isClient() && $this->invoice_id && $this->relationLoaded('invoice') && $this->invoice?->invoice_date) {
            return $this->invoice->invoice_date;
        }

        if (! $this->isClient() && $this->purchase_bill_id && $this->relationLoaded('purchaseBill') && $this->purchaseBill?->bill_date) {
            return $this->purchaseBill->bill_date;
        }

        return $this->related_document_date;
    }

    public function scopeForCompany(Builder $query, int $companyId): Builder
    {
        return $query->where('company_id', $companyId);
    }

    public function ensureShareToken(): string
    {
        if ($this->share_token) {
            return $this->share_token;
        }

        do {
            $token = Str::lower(Str::random(40));
        } while (static::where('share_token', $token)->exists());

        $this->forceFill(['share_token' => $token])->save();

        return $token;
    }

    public function publicShareUrl(): string
    {
        return route('public.debit-notes.show', $this->ensureShareToken());
    }
}
