<?php

namespace Database\Seeders;

use App\Models\{
    SuperAdmin, Company, CompanySubscription, User, Setting,
    FiscalYear, Currency, Account, Permission,
    Dimension, Customer, Vendor, TaxCode, PriceLevel,
    Uom, ItemCategory, Warehouse, Item
};
use App\Support\QuickBooksChartOfAccounts;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\{DB, Hash};

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        DB::transaction(function () {
            $this->seedSuperAdmin();
            $this->seedPermissions();
            $this->seedDemoCompany();
        });
    }

    private function seedSuperAdmin(): void
    {
        SuperAdmin::firstOrCreate(
            ['email' => 'admin@saasaccounting.com'],
            [
                'name'      => 'Super Administrator',
                'password'  => Hash::make('Admin@1234'),
                'is_active' => true,
            ]
        );
        $this->command->info('✓ Super Admin: admin@saasaccounting.com / Admin@1234');
    }

    private function seedPermissions(): void
    {
        $permissions = [
            // Accounts
            ['module'=>'accounts',      'action'=>'view',           'display_name'=>'View Chart of Accounts'],
            ['module'=>'accounts',      'action'=>'create',         'display_name'=>'Create Accounts'],
            ['module'=>'accounts',      'action'=>'edit',           'display_name'=>'Edit Accounts'],
            ['module'=>'accounts',      'action'=>'delete',         'display_name'=>'Delete Accounts'],
            // Vouchers
            ['module'=>'vouchers',      'action'=>'view',           'display_name'=>'View Vouchers'],
            ['module'=>'vouchers',      'action'=>'create',         'display_name'=>'Create Vouchers'],
            ['module'=>'vouchers',      'action'=>'edit',           'display_name'=>'Edit Vouchers'],
            ['module'=>'vouchers',      'action'=>'delete',         'display_name'=>'Delete Vouchers'],
            ['module'=>'vouchers',      'action'=>'submit',         'display_name'=>'Submit Vouchers for Approval'],
            ['module'=>'vouchers',      'action'=>'approve',        'display_name'=>'Approve Vouchers'],
            ['module'=>'vouchers',      'action'=>'post',           'display_name'=>'Post Vouchers to Ledger'],
            // AR
            ['module'=>'ar',            'action'=>'view',           'display_name'=>'View AR Documents'],
            ['module'=>'ar',            'action'=>'create',         'display_name'=>'Create AR Documents'],
            ['module'=>'ar',            'action'=>'edit',           'display_name'=>'Edit AR Documents'],
            ['module'=>'ar',            'action'=>'approve',        'display_name'=>'Approve AR Documents'],
            ['module'=>'ar',            'action'=>'post',           'display_name'=>'Post AR Documents'],
            // AP
            ['module'=>'ap',            'action'=>'view',           'display_name'=>'View AP Documents'],
            ['module'=>'ap',            'action'=>'create',         'display_name'=>'Create AP Documents'],
            ['module'=>'ap',            'action'=>'edit',           'display_name'=>'Edit AP Documents'],
            ['module'=>'ap',            'action'=>'approve',        'display_name'=>'Approve AP Documents'],
            ['module'=>'ap',            'action'=>'post',           'display_name'=>'Post AP Documents'],
            // Inventory
            ['module'=>'inventory',     'action'=>'view',           'display_name'=>'View Inventory'],
            ['module'=>'inventory',     'action'=>'create',         'display_name'=>'Create Inventory Records'],
            ['module'=>'inventory',     'action'=>'edit',           'display_name'=>'Edit Inventory Records'],
            // Manufacturing
            ['module'=>'manufacturing', 'action'=>'view',           'display_name'=>'View Manufacturing'],
            ['module'=>'manufacturing', 'action'=>'create',         'display_name'=>'Create Production Orders'],
            // Reports
            ['module'=>'reports',       'action'=>'view',           'display_name'=>'View Reports'],
            ['module'=>'reports',       'action'=>'export',         'display_name'=>'Export Reports'],
            // Settings
            ['module'=>'settings',      'action'=>'view',           'display_name'=>'View Settings'],
            ['module'=>'settings',      'action'=>'edit',           'display_name'=>'Edit Settings'],
            // Users
            ['module'=>'users',         'action'=>'view',           'display_name'=>'View Users'],
            ['module'=>'users',         'action'=>'create',         'display_name'=>'Create Users'],
            ['module'=>'users',         'action'=>'edit',           'display_name'=>'Edit Users'],
            ['module'=>'users',         'action'=>'reset_password', 'display_name'=>'Reset User Passwords'],
            // Audit
            ['module'=>'audit',         'action'=>'view',           'display_name'=>'View Audit Trail'],
            // Budget
            ['module'=>'budget',        'action'=>'view',           'display_name'=>'View Budgets'],
            ['module'=>'budget',        'action'=>'create',         'display_name'=>'Create Budgets'],
            ['module'=>'budget',        'action'=>'edit',           'display_name'=>'Edit Budgets'],
            // Banking
            ['module'=>'banking',       'action'=>'view',           'display_name'=>'View Banking'],
            ['module'=>'banking',       'action'=>'reconcile',      'display_name'=>'Bank Reconciliation'],
            // Payroll
            ['module'=>'payroll',       'action'=>'view',           'display_name'=>'View Payroll'],
            ['module'=>'payroll',       'action'=>'create',         'display_name'=>'Create Payroll Records'],
            ['module'=>'payroll',       'action'=>'edit',           'display_name'=>'Edit Payroll Records'],
            // Fixed Assets
            ['module'=>'fixed_assets', 'action'=>'view',           'display_name'=>'View Fixed Assets'],
            ['module'=>'fixed_assets', 'action'=>'create',         'display_name'=>'Create Fixed Assets'],
            ['module'=>'fixed_assets', 'action'=>'edit',           'display_name'=>'Edit Fixed Assets'],
        ];

        foreach ($permissions as $perm) {
            Permission::firstOrCreate(
                ['module' => $perm['module'], 'action' => $perm['action']],
                ['display_name' => $perm['display_name']]
            );
        }
        $this->command->info('✓ Permissions seeded: ' . count($permissions));
    }

    private function seedDemoCompany(): void
    {
        $company = Company::firstOrCreate(
            ['company_code' => 'DEMO'],
            [
                'name'       => 'Demo Company Ltd',
                'legal_name' => 'Demo Company Limited',
                'email'      => 'info@democompany.com',
                'phone'      => '+1 555 0100',
                'address'    => '123 Business Street, Suite 100',
                'city'       => 'New York',
                'country'    => 'United States',
                'status'     => 'active',
            ]
        );

        CompanySubscription::firstOrCreate(
            ['company_id' => $company->id],
            [
                'max_concurrent_users'    => 10,
                'session_timeout_minutes' => 120,
                'trial_ends_at'           => null,
                'subscription_starts_at'  => now(),
                'subscription_ends_at'    => now()->addYear(),
                'monthly_fee'             => 99.00,
                'notes'                   => 'Demo account',
            ]
        );

        // Batch-insert default settings (only if none exist yet)
        if (!Setting::where('company_id', $company->id)->exists()) {
            $rows = [];
            foreach (Setting::defaults() as $key => $value) {
                $rows[] = ['company_id' => $company->id, 'key' => $key, 'value' => $value,
                           'created_at' => now(), 'updated_at' => now()];
            }
            Setting::insert($rows);
        }

        // Fiscal year
        FiscalYear::firstOrCreate(
            ['company_id' => $company->id, 'name' => date('Y') . '-' . (date('Y') + 1)],
            [
                'start_date' => date('Y') . '-01-01',
                'end_date'   => date('Y') . '-12-31',
                'status'     => 'open',
                'is_current' => true,
            ]
        );

        // Users — withoutGlobalScopes since we're in a seeder (no tenant auth)
        User::withoutGlobalScopes()->firstOrCreate(
            ['company_id' => $company->id, 'username' => 'admin'],
            [
                'name'      => 'Demo Admin',
                'email'     => 'admin@democompany.com',
                'password'  => Hash::make('Demo@1234'),
                'is_admin'  => true,
                'is_active' => true,
            ]
        );

        User::withoutGlobalScopes()->firstOrCreate(
            ['company_id' => $company->id, 'username' => 'accountant'],
            [
                'name'      => 'Demo Accountant',
                'email'     => 'accountant@democompany.com',
                'password'  => Hash::make('Demo@1234'),
                'is_admin'  => false,
                'is_active' => true,
            ]
        );

        // Currencies
        $currencies = [
            ['code'=>'USD','name'=>'US Dollar',       'symbol'=>'$',   'is_base'=>true],
            ['code'=>'EUR','name'=>'Euro',             'symbol'=>'€',   'is_base'=>false],
            ['code'=>'GBP','name'=>'British Pound',    'symbol'=>'£',   'is_base'=>false],
            ['code'=>'BDT','name'=>'Bangladeshi Taka', 'symbol'=>'৳',   'is_base'=>false],
            ['code'=>'SAR','name'=>'Saudi Riyal',      'symbol'=>'﷼',   'is_base'=>false],
            ['code'=>'AED','name'=>'UAE Dirham',       'symbol'=>'د.إ', 'is_base'=>false],
        ];

        foreach ($currencies as $cur) {
            Currency::firstOrCreate(
                ['company_id' => $company->id, 'code' => $cur['code']],
                array_merge($cur, ['company_id' => $company->id, 'is_active' => true])
            );
        }

        $this->seedChartOfAccounts($company->id);
        $this->seedPhase3Data($company->id);
        $this->seedPhase4Data($company->id);

        $this->command->info('✓ Demo Company: code=DEMO');
        $this->command->info('  Admin:      DEMO / admin / Demo@1234');
        $this->command->info('  Accountant: DEMO / accountant / Demo@1234');
    }

    private function seedChartOfAccounts(int $companyId): void
    {
        $this->resetChartOfAccounts($companyId);

        $inserted = [];
        foreach (QuickBooksChartOfAccounts::systemAccounts() as $sortOrder => $acc) {
            $parentId = null;
            $depth = 0;
            $path = null;

            if (!empty($acc['parent']) && isset($inserted[$acc['parent']])) {
                $parent = Account::withoutGlobalScopes()->find($inserted[$acc['parent']]);
                $parentId = $parent?->id;
                $depth = ($parent?->depth ?? 0) + 1;
                $path = $parent?->path ? $parent->path . '/' . $parent->id : (string) $parent?->id;
            }

            $account = Account::withoutGlobalScopes()->updateOrCreate(
                ['company_id' => $companyId, 'code' => $acc['code']],
                [
                    'company_id'  => $companyId,
                    'parent_id'   => $parentId,
                    'name'        => $acc['name'],
                    'type'        => $acc['type'],
                    'sub_type'    => $acc['sub_type'],
                    'detail_type' => $acc['detail_type'] ?? null,
                    'is_group'    => $acc['is_group'] ?? false,
                    'is_system'   => $acc['is_system'] ?? false,
                    'is_bank'     => $acc['is_bank'] ?? false,
                    'is_cash'     => $acc['is_cash'] ?? false,
                    'is_active'   => true,
                    'sort_order'  => $sortOrder + 1,
                    'depth'       => $depth,
                    'path'        => $path,
                ]
            );

            $inserted[$acc['code']] = $account->id;
        }

        $this->command->info('✓ System Chart of Accounts seeded: ' . count($inserted) . ' accounts');
    }

    private function resetChartOfAccounts(int $companyId): void
    {
        $accountIds = Account::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->pluck('id');

        if ($accountIds->isEmpty()) {
            return;
        }

        $hasActivity = DB::table('ledger_entries')->whereIn('account_id', $accountIds)->exists()
            || DB::table('voucher_lines')->whereIn('account_id', $accountIds)->exists()
            || DB::table('bank_accounts')->whereIn('account_id', $accountIds)->exists();

        if ($hasActivity) {
            $this->command->warn('Existing accounts have activity; System accounts will be merged without deleting historical accounts.');
            return;
        }

        Account::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->forceDelete();
    }

    private function seedPhase3Data(int $companyId): void
    {
        // ── Dimensions ────────────────────────────────────────────────────────
        $dimSlots = [
            1 => 'Cost Centre',
            2 => 'Project',
            3 => 'Branch',
        ];
        foreach ($dimSlots as $slot => $name) {
            Dimension::withoutGlobalScopes()->firstOrCreate(
                ['company_id' => $companyId, 'slot' => $slot],
                ['name' => $name, 'is_active' => true]
            );
        }
        // Inactive slots
        for ($i = 4; $i <= 7; $i++) {
            Dimension::withoutGlobalScopes()->firstOrCreate(
                ['company_id' => $companyId, 'slot' => $i],
                ['name' => "Dimension {$i}", 'is_active' => false]
            );
        }

        // ── Price Levels ──────────────────────────────────────────────────────
        $priceLevels = [
            ['name' => 'Retail',     'is_default' => true],
            ['name' => 'Wholesale',  'is_default' => false],
            ['name' => 'VIP',        'is_default' => false],
        ];
        foreach ($priceLevels as $pl) {
            PriceLevel::withoutGlobalScopes()->firstOrCreate(
                ['company_id' => $companyId, 'name' => $pl['name']],
                array_merge($pl, ['company_id' => $companyId, 'is_active' => true])
            );
        }

        // ── Tax Codes ─────────────────────────────────────────────────────────
        $taxCodes = [
            ['code'=>'VAT15', 'name'=>'VAT 15%',         'rate'=>15, 'type'=>'exclusive', 'applicable_on'=>'both'],
            ['code'=>'VAT5',  'name'=>'VAT 5%',           'rate'=>5,  'type'=>'exclusive', 'applicable_on'=>'both'],
            ['code'=>'ZERO',  'name'=>'Zero Rated (0%)',  'rate'=>0,  'type'=>'exclusive', 'applicable_on'=>'both'],
            ['code'=>'EXEMPT','name'=>'Tax Exempt',       'rate'=>0,  'type'=>'exclusive', 'applicable_on'=>'both'],
        ];
        foreach ($taxCodes as $tax) {
            TaxCode::withoutGlobalScopes()->firstOrCreate(
                ['company_id' => $companyId, 'code' => $tax['code']],
                array_merge($tax, ['company_id' => $companyId, 'is_active' => true])
            );
        }

        // ── Sample Customers ──────────────────────────────────────────────────
        $customers = [
            ['code'=>'C001','name'=>'ABC Trading Co.',     'email'=>'info@abctrading.com',  'phone'=>'+1-555-0101','payment_terms_days'=>30],
            ['code'=>'C002','name'=>'XYZ Retail Store',    'email'=>'orders@xyzretail.com', 'phone'=>'+1-555-0102','payment_terms_days'=>15],
            ['code'=>'C003','name'=>'Global Imports Ltd.', 'email'=>'accounts@globalimport.com','phone'=>'+1-555-0103','payment_terms_days'=>45],
        ];
        foreach ($customers as $cust) {
            Customer::withoutGlobalScopes()->firstOrCreate(
                ['company_id' => $companyId, 'code' => $cust['code']],
                array_merge($cust, ['company_id' => $companyId, 'is_active' => true])
            );
        }

        // ── Sample Vendors ────────────────────────────────────────────────────
        $vendors = [
            ['code'=>'V001','name'=>'Prime Suppliers Inc.',  'email'=>'sales@primesuppliers.com', 'phone'=>'+1-555-0201','payment_terms_days'=>30],
            ['code'=>'V002','name'=>'Quality Materials Ltd.','email'=>'orders@qualitymat.com',    'phone'=>'+1-555-0202','payment_terms_days'=>45],
        ];
        foreach ($vendors as $vend) {
            Vendor::withoutGlobalScopes()->firstOrCreate(
                ['company_id' => $companyId, 'code' => $vend['code']],
                array_merge($vend, ['company_id' => $companyId, 'is_active' => true])
            );
        }

        $this->command->info('✓ Phase 3 data seeded: dimensions, price levels, tax codes, customers, vendors');
    }

    private function seedPhase4Data(int $companyId): void
    {
        // ── Units of Measure ──────────────────────────────────────────────────
        $uoms = [
            ['code'=>'PCS', 'name'=>'Pieces'],
            ['code'=>'KG',  'name'=>'Kilogram'],
            ['code'=>'LTR', 'name'=>'Litre'],
            ['code'=>'BOX', 'name'=>'Box'],
            ['code'=>'SET', 'name'=>'Set'],
            ['code'=>'MTR', 'name'=>'Meter'],
            ['code'=>'HRS', 'name'=>'Hours'],
        ];
        foreach ($uoms as $u) {
            Uom::withoutGlobalScopes()->firstOrCreate(
                ['company_id' => $companyId, 'code' => $u['code']],
                array_merge($u, ['company_id' => $companyId, 'is_active' => true])
            );
        }

        // ── Item Categories ───────────────────────────────────────────────────
        $categories = [
            ['code'=>'ELEC', 'name'=>'Electronics',   'parent'=>null],
            ['code'=>'FURN', 'name'=>'Furniture',     'parent'=>null],
            ['code'=>'SVC',  'name'=>'Services',      'parent'=>null],
            ['code'=>'CONS', 'name'=>'Consumables',   'parent'=>null],
        ];
        $catMap = [];
        foreach ($categories as $cat) {
            $c = ItemCategory::withoutGlobalScopes()->firstOrCreate(
                ['company_id' => $companyId, 'code' => $cat['code']],
                ['company_id' => $companyId, 'name' => $cat['name'], 'is_active' => true, 'depth' => 0]
            );
            $catMap[$cat['code']] = $c->id;
        }

        // ── Warehouses ────────────────────────────────────────────────────────
        $mainWh = Warehouse::withoutGlobalScopes()->firstOrCreate(
            ['company_id' => $companyId, 'code' => 'WH01'],
            [
                'company_id' => $companyId,
                'name'       => 'Main Warehouse',
                'type'       => 'warehouse',
                'is_active'  => true,
                'depth'      => 0,
            ]
        );

        // ── Sample Items ──────────────────────────────────────────────────────
        $pcsUom = Uom::withoutGlobalScopes()->where('company_id', $companyId)->where('code', 'PCS')->value('id');
        $hrsUom = Uom::withoutGlobalScopes()->where('company_id', $companyId)->where('code', 'HRS')->value('id');

        $items = [
            [
                'code'             => 'ITEM001',
                'name'             => 'Sample Product A',
                'type'             => 'inventory',
                'category_id'      => $catMap['ELEC'] ?? null,
                'uom_id'           => $pcsUom,
                'default_warehouse_id' => $mainWh->id,
                'valuation_method' => 'weighted_average',
                'tracking_type'    => 'none',
                'reorder_level'    => 10,
                'is_sold'          => true,
                'is_purchased'     => true,
            ],
            [
                'code'             => 'ITEM002',
                'name'             => 'Sample Product B',
                'type'             => 'inventory',
                'category_id'      => $catMap['CONS'] ?? null,
                'uom_id'           => $pcsUom,
                'default_warehouse_id' => $mainWh->id,
                'valuation_method' => 'weighted_average',
                'tracking_type'    => 'lot',
                'reorder_level'    => 5,
                'is_sold'          => true,
                'is_purchased'     => true,
            ],
            [
                'code'             => 'SVC001',
                'name'             => 'Consultation Service',
                'type'             => 'service',
                'category_id'      => $catMap['SVC'] ?? null,
                'uom_id'           => $hrsUom,
                'default_warehouse_id' => null,
                'valuation_method' => 'weighted_average',
                'tracking_type'    => 'none',
                'reorder_level'    => 0,
                'is_sold'          => true,
                'is_purchased'     => false,
            ],
        ];

        foreach ($items as $itemData) {
            Item::withoutGlobalScopes()->firstOrCreate(
                ['company_id' => $companyId, 'code' => $itemData['code']],
                array_merge($itemData, ['company_id' => $companyId, 'is_active' => true])
            );
        }

        $this->command->info('✓ Phase 4 data seeded: UOMs, categories, warehouses, items');
    }
}
