<?php

namespace App\Models;

use App\Helpers\AddressFormatter;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Vendor extends Model
{
    protected $fillable = [
        'company_id', 'name', 'vendor_code', 'contact_person', 'contact_phone', 'contact_email',
        'email', 'phone', 'gstin', 'gst_treatment', 'pan', 'tan', 'vat', 'website', 'currency',
        'also_use_as_client', 'use_for_dispatch',
        'address', 'billing_address_line1', 'billing_address_line2',
        'city', 'state', 'pincode', 'country',
        'ship_to_my_address', 'ship_to_different_address',
        'shipping_address_line1', 'shipping_address_line2',
        'shipping_city', 'shipping_state', 'shipping_pincode', 'shipping_country',
        'opening_balance', 'balance_type', 'notes', 'other_info',
        'additional_contacts', 'is_active',
    ];

    protected $casts = [
        'opening_balance' => 'decimal:2',
        'also_use_as_client' => 'boolean',
        'use_for_dispatch' => 'boolean',
        'ship_to_my_address' => 'boolean',
        'ship_to_different_address' => 'boolean',
        'is_active' => 'boolean',
        'additional_contacts' => 'array',
    ];

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

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

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

    public function signedOpeningBalance(): float
    {
        $amount = (float) $this->opening_balance;

        return $this->balance_type === 'debit' ? -$amount : $amount;
    }

    public function currentBalance(): float
    {
        $opening = $this->signedOpeningBalance();

        $unpaid = (float) $this->purchaseBills()
            ->whereNotIn('status', ['cancelled', 'draft'])
            ->selectRaw('COALESCE(SUM(grand_total - paid_amount), 0) as total')
            ->value('total');

        $paid = (float) $this->payments()
            ->where('payment_type', 'made')
            ->sum('amount');

        return round($opening + $unpaid - $paid, 2);
    }

    public function gstTreatmentLabel(): string
    {
        return config('customer.gst_treatments.'.$this->gst_treatment, $this->gst_treatment ?: '—');
    }

    public function billingAddressLines(): array
    {
        $lines = AddressFormatter::lines(
            $this->billing_address_line1,
            $this->billing_address_line2,
            $this->city,
            $this->state,
            $this->pincode,
            $this->country,
        );

        if (empty($lines) && $this->address) {
            return array_values(array_filter(explode("\n", $this->address)));
        }

        return $lines;
    }

    public function billingAddressShort(int $max = 42): string
    {
        $line = $this->billing_address_line1 ?: ($this->billingAddressLines()[0] ?? '');

        return strlen($line) > $max ? substr($line, 0, $max).'...' : ($line ?: '—');
    }

    public function toPickerArray(): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'city' => $this->city,
            'state' => $this->state,
            'gstin' => $this->gstin,
            'gst_treatment' => $this->gst_treatment,
            'gst_treatment_label' => $this->gstTreatmentLabel(),
            'billing_short' => $this->billingAddressShort(120),
            'balance' => $this->currentBalance(),
        ];
    }

    public function contactPersonsList(): array
    {
        $persons = [];

        if ($this->contact_person) {
            $persons[] = $this->contact_person;
        }

        foreach ($this->additional_contacts ?? [] as $contact) {
            if (! empty($contact['name'])) {
                $persons[] = $contact['name'];
            }
        }

        if (empty($persons)) {
            $persons[] = $this->name;
        }

        return $persons;
    }
}
