<?php

namespace Database\Seeders;

use App\Enums\AccountType;
use App\Enums\NormalBalance;
use App\Enums\TaxCategory;
use App\Models\Account;
use App\Models\AccountingPeriod;
use App\Models\Branch;
use App\Models\Company;
use App\Models\CostCenter;
use App\Models\Department;
use App\Models\FiscalYear;
use App\Models\Permission;
use App\Models\Role;
use App\Models\ServiceType;
use App\Models\TaxCode;
use App\Models\TransportRoute;
use Carbon\Carbon;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

final class FoundationSeeder extends Seeder
{
    public function run(): void
    {
        DB::transaction(function (): void {
            $company=Company::query()->first() ?? Company::query()->create(['legal_name'=>'Sample UAE Transport LLC','trade_name'=>'Sample Transport','country_code'=>'AE','base_currency'=>'AED','timezone'=>'Asia/Dubai','vat_registered'=>true,'is_active'=>true]);
            $branch=Branch::query()->firstOrCreate(['company_id'=>$company->id,'code'=>'HO'],['name'=>'Head Office','emirate'=>'Abu Dhabi','is_active'=>true]);
            Department::query()->firstOrCreate(['company_id'=>$company->id,'code'=>'OPS'],['branch_id'=>$branch->id,'name'=>'Operations','is_active'=>true]);
            Department::query()->firstOrCreate(['company_id'=>$company->id,'code'=>'FIN'],['branch_id'=>$branch->id,'name'=>'Finance','is_active'=>true]);
            CostCenter::query()->firstOrCreate(['company_id'=>$company->id,'code'=>'HO'],['branch_id'=>$branch->id,'name'=>'Head Office','is_active'=>true]);
            $accounts=$this->seedAccounts($company->id);
            $this->seedPeriods($company->id);
            $this->seedTaxCodes($company->id,$accounts);
            $this->seedOperations($company->id,$accounts);
            $this->seedPermissionsAndRoles($company->id);
        });
    }

    /** @return array<string,Account> */
    private function seedAccounts(int $companyId): array
    {
        $rows=[
            ['1000','Cash on Hand',AccountType::ASSET,NormalBalance::DEBIT,false,'cash_bank'],
            ['1010','Petty Cash',AccountType::ASSET,NormalBalance::DEBIT,false,'petty_cash'],
            ['1020','Bank Accounts',AccountType::ASSET,NormalBalance::DEBIT,false,'bank_accounts'],
            ['1100','Accounts Receivable',AccountType::ASSET,NormalBalance::DEBIT,true,'accounts_receivable'],
            ['1150','Employee Advances',AccountType::ASSET,NormalBalance::DEBIT,true,'employee_advances'],
            ['1160','Driver Advances',AccountType::ASSET,NormalBalance::DEBIT,true,'driver_advances'],
            ['1200','Vendor Advances',AccountType::ASSET,NormalBalance::DEBIT,true,'vendor_advances'],
            ['1300','Input VAT Recoverable',AccountType::ASSET,NormalBalance::DEBIT,true,'input_vat'],
            ['1400','Prepaid Expenses',AccountType::ASSET,NormalBalance::DEBIT,false,'prepaid_expenses'],
            ['1500','Deposits',AccountType::ASSET,NormalBalance::DEBIT,false,'deposits'],
            ['1600','Vehicles and Fleet Assets',AccountType::ASSET,NormalBalance::DEBIT,false,'vehicle_assets'],
            ['1690','Accumulated Depreciation - Vehicles',AccountType::ASSET,NormalBalance::CREDIT,false,'accumulated_depreciation'],
            ['2000','Accounts Payable',AccountType::LIABILITY,NormalBalance::CREDIT,true,'accounts_payable'],
            ['2100','Customer Advances',AccountType::LIABILITY,NormalBalance::CREDIT,true,'customer_advances'],
            ['2200','Output VAT Payable',AccountType::LIABILITY,NormalBalance::CREDIT,true,'output_vat'],
            ['2250','VAT Payable / Receivable',AccountType::LIABILITY,NormalBalance::CREDIT,true,'vat_payable'],
            ['2300','Accrued Expenses',AccountType::LIABILITY,NormalBalance::CREDIT,false,'accrued_expenses'],
            ['2400','Loans and Finance',AccountType::LIABILITY,NormalBalance::CREDIT,false,'loans'],
            ['2500','Security Deposits Received',AccountType::LIABILITY,NormalBalance::CREDIT,false,'security_deposits_received'],
            ['3000','Owner Capital',AccountType::EQUITY,NormalBalance::CREDIT,false,'owner_capital'],
            ['3100','Retained Earnings',AccountType::EQUITY,NormalBalance::CREDIT,false,'retained_earnings'],
            ['3200','Drawings',AccountType::EQUITY,NormalBalance::DEBIT,false,'drawings'],
            ['4000','Transport Income',AccountType::INCOME,NormalBalance::CREDIT,false,'transport_income'],
            ['4010','Delivery Income',AccountType::INCOME,NormalBalance::CREDIT,false,'delivery_income'],
            ['4020','Vehicle Rental Income',AccountType::INCOME,NormalBalance::CREDIT,false,'rental_income'],
            ['4030','Handling and Loading Income',AccountType::INCOME,NormalBalance::CREDIT,false,'handling_income'],
            ['4040','Detention and Waiting Income',AccountType::INCOME,NormalBalance::CREDIT,false,'detention_income'],
            ['4050','Fuel Surcharge Income',AccountType::INCOME,NormalBalance::CREDIT,false,'fuel_surcharge_income'],
            ['4060','Salik and Toll Recovery',AccountType::INCOME,NormalBalance::CREDIT,false,'toll_recovery_income'],
            ['4090','Other Service Income',AccountType::INCOME,NormalBalance::CREDIT,false,'other_income'],
            ['5000','Vendor Transport Cost',AccountType::COST_OF_REVENUE,NormalBalance::DEBIT,false,'vendor_transport_cost'],
            ['5010','Subcontractor Cost',AccountType::COST_OF_REVENUE,NormalBalance::DEBIT,false,'subcontractor_cost'],
            ['5020','Driver Trip Cost',AccountType::COST_OF_REVENUE,NormalBalance::DEBIT,false,'driver_trip_cost'],
            ['5030','Fuel - Direct Trips',AccountType::COST_OF_REVENUE,NormalBalance::DEBIT,false,'fuel_cost'],
            ['5040','Salik and Toll Cost',AccountType::COST_OF_REVENUE,NormalBalance::DEBIT,false,'toll_cost'],
            ['5050','Loading and Offloading Cost',AccountType::COST_OF_REVENUE,NormalBalance::DEBIT,false,'loading_cost'],
            ['5060','Route and Permit Cost',AccountType::COST_OF_REVENUE,NormalBalance::DEBIT,false,'permit_cost'],
            ['5090','Other Direct Trip Cost',AccountType::COST_OF_REVENUE,NormalBalance::DEBIT,false,'other_direct_cost'],
            ['6000','Salaries and Wages',AccountType::EXPENSE,NormalBalance::DEBIT,false,'salaries'],
            ['6010','Rent',AccountType::EXPENSE,NormalBalance::DEBIT,false,'rent'],
            ['6020','Utilities',AccountType::EXPENSE,NormalBalance::DEBIT,false,'utilities'],
            ['6030','Office Expenses',AccountType::EXPENSE,NormalBalance::DEBIT,false,'operating_expenses'],
            ['6040','Vehicle Maintenance',AccountType::EXPENSE,NormalBalance::DEBIT,false,'vehicle_maintenance'],
            ['6050','Insurance',AccountType::EXPENSE,NormalBalance::DEBIT,false,'insurance'],
            ['6060','Vehicle Registration',AccountType::EXPENSE,NormalBalance::DEBIT,false,'registration_expense'],
            ['6070','Fines and Penalties',AccountType::EXPENSE,NormalBalance::DEBIT,false,'fines'],
            ['6080','Telephone and Internet',AccountType::EXPENSE,NormalBalance::DEBIT,false,'telecom'],
            ['6090','Professional Fees',AccountType::EXPENSE,NormalBalance::DEBIT,false,'professional_fees'],
            ['6100','Marketing',AccountType::EXPENSE,NormalBalance::DEBIT,false,'marketing'],
            ['6110','Depreciation',AccountType::EXPENSE,NormalBalance::DEBIT,false,'depreciation'],
            ['6120','Bank Charges',AccountType::EXPENSE,NormalBalance::DEBIT,false,'bank_charges'],
            ['6190','Other Operating Expenses',AccountType::EXPENSE,NormalBalance::DEBIT,false,'other_expenses'],
        ];
        $result=[];
        foreach($rows as[$code,$name,$type,$normal,$control,$key]){$result[$key]=Account::query()->firstOrCreate(['company_id'=>$companyId,'code'=>$code],['name'=>$name,'type'=>$type,'normal_balance'=>$normal,'is_control_account'=>$control,'is_active'=>true,'system_key'=>$key]);}
        return$result;
    }

    private function seedPeriods(int $companyId): void
    {
        $startMonth=(int)(Company::find($companyId)?->financial_year_start_month??1);$year=now()->month<$startMonth?now()->year-1:now()->year;$starts=Carbon::create($year,$startMonth,1)->startOfDay();$ends=$starts->copy()->addYear()->subDay();
        $fiscal=FiscalYear::query()->firstOrCreate(['company_id'=>$companyId,'starts_on'=>$starts->toDateString(),'ends_on'=>$ends->toDateString()],['name'=>$starts->format('Y').'-'.$ends->format('Y'),'status'=>'open']);
        $cursor=$starts->copy();while($cursor->lte($ends)){$end=$cursor->copy()->endOfMonth()->min($ends);AccountingPeriod::query()->firstOrCreate(['fiscal_year_id'=>$fiscal->id,'starts_on'=>$cursor->toDateString(),'ends_on'=>$end->toDateString()],['name'=>$cursor->format('F Y'),'is_locked'=>false]);$cursor=$cursor->copy()->addMonth()->startOfMonth();}
    }

    /** @param array<string,Account> $accounts */
    private function seedTaxCodes(int $companyId,array $accounts):void
    {
        $rows=[['STD5','Standard Rated 5%',TaxCategory::STANDARD,'5.0000','100.0000',true,true],['ZERO','Zero Rated',TaxCategory::ZERO_RATED,'0.0000','100.0000',false,true],['EXEMPT','Exempt',TaxCategory::EXEMPT,'0.0000','0.0000',false,true],['OOS','Out of Scope',TaxCategory::OUT_OF_SCOPE,'0.0000','0.0000',false,false],['RC5','Reverse Charge 5%',TaxCategory::REVERSE_CHARGE,'5.0000','100.0000',false,true]];
        foreach($rows as[$code,$name,$category,$rate,$recoverable,$trn,$evidence])TaxCode::query()->firstOrCreate(['company_id'=>$companyId,'code'=>$code],['name'=>$name,'category'=>$category,'rate'=>$rate,'recoverable_percentage'=>$recoverable,'output_account_id'=>$accounts['output_vat']->id,'input_account_id'=>$accounts['input_vat']->id,'reverse_charge_output_account_id'=>$accounts['output_vat']->id,'reverse_charge_input_account_id'=>$accounts['input_vat']->id,'is_active'=>true,'requires_trn'=>$trn,'requires_evidence'=>$evidence]);
    }

    /** @param array<string,Account> $accounts */
    private function seedOperations(int $companyId,array $accounts):void
    {
        $std=TaxCode::where('company_id',$companyId)->where('code','STD5')->first();
        $services=['LOCAL'=>'Local Transportation','INTEREM'=>'Inter-Emirate Transportation','INTL'=>'International Transportation','CARGO'=>'Cargo Delivery','CONTAINER'=>'Container Transport','PASSENGER'=>'Passenger Transport','RENTAL-D'=>'Vehicle Rental with Driver','RENTAL-ND'=>'Vehicle Rental without Driver','LASTMILE'=>'Last-Mile Delivery','MOVING'=>'Moving Service','COURIER'=>'Courier Service','CONTRACT'=>'Contract Transportation'];
        foreach($services as $code=>$name)ServiceType::query()->firstOrCreate(['company_id'=>$companyId,'code'=>$code],['name'=>$name,'default_tax_code_id'=>$std?->id,'default_income_account_id'=>$accounts['transport_income']->id,'default_cost_account_id'=>$accounts['vendor_transport_cost']->id,'is_active'=>true]);
        foreach([['AUH-DXB','Abu Dhabi to Dubai','Abu Dhabi','Dubai'],['DXB-AUH','Dubai to Abu Dhabi','Dubai','Abu Dhabi'],['AUH-AUH','Abu Dhabi Local','Abu Dhabi','Abu Dhabi'],['DXB-DXB','Dubai Local','Dubai','Dubai'],['SHJ-DXB','Sharjah to Dubai','Sharjah','Dubai']] as[$code,$name,$from,$to])TransportRoute::query()->firstOrCreate(['company_id'=>$companyId,'code'=>$code],['name'=>$name,'origin'=>$from,'destination'=>$to,'origin_country'=>'AE','destination_country'=>'AE','is_active'=>true]);
    }

    private function seedPermissionsAndRoles(int $companyId):void
    {
        $modules=['branches','accounts','tax_settings','periods','parties','service_types','routes','vehicles','drivers','vehicle_maintenance','fuel_entries','driver_advances','transport_jobs','trips','contracts','rate_cards','quotations','customer_invoices','vendor_bills','receipts','payments','expenses','adjustment_notes','contra_settlements','bank_accounts','bank_reconciliation','journals','reports','users','roles','company_settings','audit_logs','einvoices','ai_assistant'];
        $actions=['view','create','edit_draft','submit','approve','reject','post','reverse','print','export','delete_draft','manage'];$permissions=[];
        foreach($modules as $module){foreach($actions as $action){$slug=$module.'.'.$action;$permissions[$slug]=Permission::query()->firstOrCreate(['slug'=>$slug],['name'=>ucwords(str_replace('_',' ',$module.' '.$action)),'module'=>$module,'action'=>$action]);}}
        foreach(['branches.view_all','transport_jobs.override_rate','transport_jobs.invoice_without_pod','customer_invoices.override_credit_limit','periods.reopen','einvoices.submit','einvoices.retry','reports.view_cost','reports.view_profit'] as $slug){[$module,$action]=explode('.',$slug,2);$permissions[$slug]=Permission::query()->firstOrCreate(['slug'=>$slug],['name'=>ucwords(str_replace(['_','.'],' ',$slug)),'module'=>$module,'action'=>$action]);}
        $roles=[
            'super-administrator'=>['name'=>'Super Administrator','all'=>true],
            'company-owner'=>['name'=>'Company Owner','prefixes'=>['reports.','transport_jobs.view','trips.view','parties.view','quotations.view','customer_invoices.view','vendor_bills.view','receipts.view','payments.view','expenses.view','driver_advances.view','journals.view','branches.view_all']],
            'finance-manager'=>['name'=>'Finance Manager','prefixes'=>['accounts.','tax_settings.','periods.','parties.','quotations.','customer_invoices.','vendor_bills.','receipts.','payments.','expenses.','driver_advances.','adjustment_notes.','contra_settlements.','bank_accounts.','bank_reconciliation.','journals.','reports.','audit_logs.view','branches.view_all']],
            'accountant'=>['name'=>'Accountant','prefixes'=>['accounts.view','tax_settings.view','periods.view','parties.view','quotations.','customer_invoices.','vendor_bills.','receipts.','payments.','expenses.','driver_advances.','adjustment_notes.','contra_settlements.','bank_reconciliation.','journals.','reports.']],
            'cashier'=>['name'=>'Cashier','prefixes'=>['parties.view','receipts.','payments.','bank_accounts.view']],
            'transport-manager'=>['name'=>'Transport Manager','prefixes'=>['transport_jobs.','trips.','vehicles.','drivers.','vehicle_maintenance.','fuel_entries.','driver_advances.','service_types.view','routes.view','contracts.view','rate_cards.view','parties.view','reports.view','reports.view_cost','reports.view_profit']],
            'dispatcher'=>['name'=>'Dispatcher','prefixes'=>['transport_jobs.view','transport_jobs.create','transport_jobs.edit_draft','trips.','vehicles.view','drivers.view','routes.view','parties.view']],
            'operations-staff'=>['name'=>'Operations Staff','prefixes'=>['transport_jobs.view','transport_jobs.create','transport_jobs.edit_draft','trips.view','trips.create','trips.edit_draft','vehicles.view','drivers.view','parties.view']],
            'fleet-manager'=>['name'=>'Fleet Manager','prefixes'=>['vehicles.','drivers.','vehicle_maintenance.','fuel_entries.','driver_advances.','trips.view','transport_jobs.view','reports.view']],
            'branch-manager'=>['name'=>'Branch Manager','prefixes'=>['transport_jobs.','trips.','parties.','customer_invoices.view','vendor_bills.view','receipts.view','payments.view','expenses.view','reports.view']],
            'auditor'=>['name'=>'Auditor','prefixes'=>['accounts.view','tax_settings.view','parties.view','quotations.view','customer_invoices.view','vendor_bills.view','receipts.view','payments.view','expenses.view','adjustment_notes.view','contra_settlements.view','journals.view','reports.view','audit_logs.view','branches.view_all']],
            'read-only-management'=>['name'=>'Read-only Management','prefixes'=>['transport_jobs.view','trips.view','parties.view','quotations.view','customer_invoices.view','vendor_bills.view','receipts.view','payments.view','expenses.view','reports.view']],
        ];
        foreach($roles as $slug=>$setup){$role=Role::query()->firstOrCreate(['company_id'=>$companyId,'slug'=>$slug],['name'=>$setup['name'],'is_system'=>true]);$ids=collect($permissions)->filter(function($permission,$permissionSlug)use($setup){if($setup['all']??false)return true;foreach($setup['prefixes']??[] as $prefix){if(str_ends_with($prefix,'.')&&str_starts_with($permissionSlug,$prefix))return true;if($permissionSlug===$prefix)return true;}return false;})->pluck('id');$role->permissions()->sync($ids);}
    }
}
