<?php

namespace Database\Seeders;

use App\Models\User;
use App\Models\Party;
use App\Models\Yarn;
use App\Models\Account;
use App\Models\Purchase;
use App\Models\PurchaseItem;
use App\Models\Sale;
use App\Models\SaleItem;
use App\Models\StockLedger;
use App\Models\Voucher;
use App\Models\CompanySetting;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
use Carbon\Carbon;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        // 1. Company Settings
        CompanySetting::firstOrCreate(
            ['id' => 1],
            [
                'company_name'   => 'ABC YARN HOUSE',
                'tagline'       => 'Premium Quality Yarn Supplier',
                'address'       => '12 Industrial Area, Dhaka-1205, Bangladesh',
                'phone'         => '+880 1700-123456',
                'email'         => 'info@abcyarnhouse.com',
                'website'       => 'www.abcyarnhouse.com',
                'currency'      => '৳',
                'currency_code' => 'BDT',
                'timezone'      => 'Asia/Dhaka',
                'date_format'   => 'Y-m-d',
            ]
        );

        // 2. Admin User
        User::firstOrCreate(
            ['email' => 'admin@abcyarnhouse.com'],
            [
                'name'     => 'Administrator',
                'password' => Hash::make('password'),
                'role'     => 'admin',
                'phone'    => '+880 1700-123456',
            ]
        );

        // 3. Accounts
        $cash = Account::firstOrCreate(['code' => 'CASH-001'], [
            'name'             => 'Cash in Hand',
            'type'             => 'cash',
            'opening_balance'  => 500000,
            'current_balance'  => 500000,
            'is_active'        => true,
        ]);

        Account::firstOrCreate(['code' => 'BANK-HBL-001'], [
            'name'            => 'HBL Bank - Main A/C',
            'type'            => 'bank',
            'bank_name'       => 'Habib Bank Limited',
            'account_number'  => '1234-5678901234',
            'branch'          => 'Gulshan Branch',
            'opening_balance' => 1000000,
            'current_balance' => 1000000,
            'is_active'       => true,
        ]);

        Account::firstOrCreate(['code' => 'BANK-EBL-001'], [
            'name'            => 'EBL Bank - Business A/C',
            'type'            => 'bank',
            'bank_name'       => 'Eastern Bank Limited',
            'account_number'  => '9876-5432109876',
            'branch'          => 'Dhanmondi Branch',
            'opening_balance' => 750000,
            'current_balance' => 750000,
            'is_active'       => true,
        ]);

        // 4. Suppliers
        $suppliers = [
            ['name' => 'ABC Textiles Ltd', 'phone' => '+880 1700-111111', 'email' => 'info@abctextiles.com', 'city' => 'Dhaka'],
            ['name' => 'XYZ Spinning Mills', 'phone' => '+880 1800-222222', 'email' => 'contact@xyzspinning.com', 'city' => 'Gazipur'],
            ['name' => 'Global Yarn Corporation', 'phone' => '+880 1900-333333', 'email' => 'sales@globalyarn.com', 'city' => 'Narayanganj'],
            ['name' => 'Premium Fibers Co.', 'phone' => '+880 1600-444444', 'email' => 'info@premiumfibers.com', 'city' => 'Savar'],
            ['name' => 'Star Spinning Ltd', 'phone' => '+880 1500-555555', 'email' => 'star@spinningltd.com', 'city' => 'Chittagong'],
        ];

        foreach ($suppliers as $data) {
            Party::firstOrCreate(
                ['phone' => $data['phone']],
                [
                    'type'             => 'supplier',
                    'name'            => $data['name'],
                    'code'            => strtoupper(substr($data['name'], 0, 3)) . '-' . str_pad(Party::count() + 1, 4, '0', STR_PAD_LEFT),
                    'contact_person'  => 'Purchase Manager',
                    'email'           => $data['email'],
                    'address'         => $data['city'] . ', Bangladesh',
                    'city'            => $data['city'],
                    'country'         => 'Bangladesh',
                    'opening_balance' => 0,
                    'balance_type'    => 'credit',
                    'credit_limit'    => 5000000,
                    'is_active'      => true,
                ]
            );
        }

        // 5. Customers
        $customers = [
            ['name' => 'Textile Corp BD', 'phone' => '+880 1800-111111', 'email' => 'accounts@textilecorpbd.com'],
            ['name' => 'Fashion Hub Ltd', 'phone' => '+880 1900-222222', 'email' => 'procurement@fashionhub.com'],
            ['name' => 'Garments Plus', 'phone' => '+880 1700-333333', 'email' => 'buy@garmentsplus.com'],
            ['name' => 'Knit World Factory', 'phone' => '+880 1600-444444', 'email' => 'factory@knitworld.com'],
            ['name' => 'Design Studio International', 'phone' => '+880 1500-555555', 'email' => 'design@dsibd.com'],
        ];

        foreach ($customers as $data) {
            Party::firstOrCreate(
                ['phone' => $data['phone']],
                [
                    'type'             => 'customer',
                    'name'            => $data['name'],
                    'code'            => 'CUS-' . str_pad(Party::count() + 1, 4, '0', STR_PAD_LEFT),
                    'contact_person'  => 'Procurement Head',
                    'email'           => $data['email'],
                    'city'            => 'Dhaka',
                    'country'         => 'Bangladesh',
                    'opening_balance' => 0,
                    'balance_type'   => 'credit',
                    'credit_limit'    => 2000000,
                    'is_active'      => true,
                ]
            );
        }

        // 6. Yarns
        $yarns = [
            ['name' => 'Cotton 30s', 'code' => 'CTN-30S', 'category' => 'Cotton', 'count' => '30s', 'reorder_level' => 500],
            ['name' => 'Cotton 40s', 'code' => 'CTN-40S', 'category' => 'Cotton', 'count' => '40s', 'reorder_level' => 500],
            ['name' => 'Polyester 30s', 'code' => 'POL-30S', 'category' => 'Polyester', 'count' => '30s', 'reorder_level' => 300],
            ['name' => 'Polyester 40s', 'code' => 'POL-40S', 'category' => 'Polyester', 'count' => '40s', 'reorder_level' => 300],
            ['name' => 'Wool Blend 30s', 'code' => 'WBL-30S', 'category' => 'Wool Blend', 'count' => '30s', 'reorder_level' => 100],
            ['name' => 'Silk Premium', 'code' => 'SLK-PRM', 'category' => 'Silk', 'count' => 'Premium', 'reorder_level' => 50],
        ];

        foreach ($yarns as $data) {
            Yarn::firstOrCreate(['code' => $data['code']], $data);
        }

        // 7. Create sample purchases and sales (last 30 days)
        $this->createTransactions();
    }

    private function createTransactions(): void
    {
        $suppliers = Party::suppliers()->get();
        $customers = Party::customers()->get();
        $yarns = Yarn::active()->get();
        $cashAccount = Account::where('type', 'cash')->first();
        $bankAccount = Account::where('type', 'bank')->first();

        // Create 25 purchases over last 30 days
        for ($i = 0; $i < 25; $i++) {
            $date = Carbon::today()->subDays(rand(1, 30));
            $supplier = $suppliers->random();
            $items = [];
            $totalQty = 0;

            foreach ($yarns->random(rand(1, 3)) as $yarn) {
                $qty = rand(100, 500);
                $rate = $this->getRate($yarn->name);
                $totalQty += $qty;

                $items[] = [
                    'yarn_id'   => $yarn->id,
                    'lot_no'    => 'L-' . date('ymd') . rand(100, 999),
                    'bags'      => (int) ceil($qty / 30),
                    'quantity'  => $qty,
                    'unit'      => 'Kg',
                    'rate'      => $rate,
                ];
            }

            $subtotal = collect($items)->sum(fn ($i) => $i['quantity'] * $i['rate']);
            $labourCharge = rand(500, 2000);
            $carRent = rand(300, 1500);
            $grandTotal = $subtotal + $labourCharge + $carRent;
            $paid = rand(0, 1) ? $grandTotal : ($grandTotal * rand(0, 8) / 10);

            $purchase = Purchase::create([
                'voucher_no'    => Purchase::generateVoucherNo(),
                'party_id'      => $supplier->id,
                'purchase_date' => $date,
                'invoice_no'    => 'INV-' . $date->format('ymd') . '-' . rand(100, 999),
                'subtotal'      => $subtotal,
                'labour_charge' => $labourCharge,
                'car_rent'      => $carRent,
                'grand_total'   => $grandTotal,
                'paid_amount'   => $paid,
                'due_amount'    => $grandTotal - $paid,
                'status'        => 'posted',
            ]);

            foreach ($items as $item) {
                $item['purchase_id'] = $purchase->id;
                PurchaseItem::create($item);

                // Stock ledger entry
                StockLedger::create([
                    'transaction_date' => $date,
                    'yarn_id'         => $item['yarn_id'],
                    'lot_no'          => $item['lot_no'],
                    'type'            => 'purchase',
                    'reference_type'  => Purchase::class,
                    'reference_id'    => $purchase->id,
                    'voucher_no'      => $purchase->voucher_no,
                    'in_qty'          => $item['quantity'],
                    'out_qty'         => 0,
                    'rate'            => $item['rate'],
                    'value'           => $item['quantity'] * $item['rate'],
                    'remarks'         => 'Purchase from ' . $supplier->name,
                ]);
            }

            // Payment voucher if partially/fully paid
            if ($paid > 0) {
                Voucher::create([
                    'type'         => 'payment',
                    'voucher_date'=> $date,
                    'account_id'  => rand(0, 1) ? $cashAccount->id : $bankAccount->id,
                    'party_id'    => $supplier->id,
                    'amount'      => $paid,
                    'mode'        => rand(0, 1) ? 'cash' : 'bank transfer',
                    'description' => 'Payment for ' . $purchase->voucher_no,
                    'status'      => 'posted',
                ]);
            }
        }

        // Create 30 sales over last 30 days
        for ($i = 0; $i < 30; $i++) {
            $date = Carbon::today()->subDays(rand(0, 30));
            $customer = $customers->random();
            $items = [];
            $totalQty = 0;

            foreach ($yarns->random(rand(1, 4)) as $yarn) {
                $qty = rand(50, 300);
                $rate = $this->getRate($yarn->name) * 1.15; // 15% margin
                $totalQty += $qty;

                $items[] = [
                    'yarn_id'   => $yarn->id,
                    'lot_no'    => 'L-' . date('ymd') . rand(100, 999),
                    'bags'      => (int) ceil($qty / 30),
                    'quantity'  => $qty,
                    'unit'      => 'Kg',
                    'rate'      => round($rate, 2),
                ];
            }

            $subtotal = collect($items)->sum(fn ($i) => $i['quantity'] * $i['rate']);
            $labourCharge = rand(200, 1000);
            $carRent = rand(200, 800);
            $grandTotal = $subtotal + $labourCharge + $carRent;
            $paid = rand(0, 1) ? $grandTotal : ($grandTotal * rand(0, 7) / 10);

            $sale = Sale::create([
                'voucher_no'    => Sale::generateVoucherNo(),
                'party_id'      => $customer->id,
                'sales_date'    => $date,
                'invoice_no'    => 'INV-' . $date->format('ymd') . '-' . rand(100, 999),
                'subtotal'      => $subtotal,
                'labour_charge' => $labourCharge,
                'car_rent'      => $carRent,
                'grand_total'   => $grandTotal,
                'paid_amount'  => $paid,
                'due_amount'    => $grandTotal - $paid,
                'status'       => 'posted',
            ]);

            foreach ($items as $item) {
                $item['sale_id'] = $sale->id;
                SaleItem::create($item);

                // Stock ledger entry
                StockLedger::create([
                    'transaction_date' => $date,
                    'yarn_id'         => $item['yarn_id'],
                    'lot_no'          => $item['lot_no'],
                    'type'            => 'sale',
                    'reference_type'  => Sale::class,
                    'reference_id'    => $sale->id,
                    'voucher_no'      => $sale->voucher_no,
                    'in_qty'          => 0,
                    'out_qty'         => $item['quantity'],
                    'rate'            => $item['rate'],
                    'value'           => $item['quantity'] * $item['rate'],
                    'remarks'         => 'Sale to ' . $customer->name,
                ]);
            }

            // Receipt voucher if payment received
            if ($paid > 0) {
                Voucher::create([
                    'type'         => 'receipt',
                    'voucher_date'=> $date,
                    'account_id'  => rand(0, 1) ? $cashAccount->id : $bankAccount->id,
                    'party_id'    => $customer->id,
                    'amount'      => $paid,
                    'mode'        => rand(0, 1) ? 'cash' : 'bank transfer',
                    'description' => 'Receipt for ' . $sale->voucher_no,
                    'status'      => 'posted',
                ]);
            }
        }
    }

    private function getRate(string $yarnName): float
    {
        return match (true) {
            str_contains($yarnName, 'Cotton 30s') => 310 + rand(-10, 20),
            str_contains($yarnName, 'Cotton 40s') => 340 + rand(-10, 20),
            str_contains($yarnName, 'Polyester 30s') => 280 + rand(-10, 15),
            str_contains($yarnName, 'Polyester 40s') => 290 + rand(-10, 15),
            str_contains($yarnName, 'Wool') => 420 + rand(-15, 25),
            str_contains($yarnName, 'Silk') => 700 + rand(-20, 40),
            default => 300 + rand(-10, 20),
        };
    }
}
