<?php

namespace App\Services;

use App\Models\Bill;
use App\Models\ChartOfAccount;
use App\Models\JournalEntry;
use App\Models\JournalEntryItem;
use App\Models\MaintenanceRecord;
use App\Models\PayrollRecord;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class AccountingService
{
    /**
     * Create a Journal Entry from a Bill
     */
    public function postBillToLedger(Bill $bill)
    {
        // 1. Get/Create necessary accounts
        $apAccount = $this->getOrInitAccount('2100', 'Accounts Payable', 'LIABILITY', 'CREDIT');
        $inventoryAccount = $this->getOrInitAccount('1200', 'Inventory Asset', 'ASSET', 'DEBIT');

        // 2. Create Journal Entry Header
        $entryNumber = 'JE-' . date('Ymd') . '-' . strtoupper(Str::random(4));
        
        $journalEntry = JournalEntry::create([
            'entry_number' => $entryNumber,
            'date' => $bill->issue_date,
            'description' => "Bill Posting #{$bill->bill_number} - Supplier: " . $bill->supplier->name,
            'reference' => 'BILL-' . $bill->bill_number,
            'total_debit' => $bill->total_amount,
            'total_credit' => $bill->total_amount,
            'status' => 'POSTED',
            'created_by' => auth()->id() ?? $bill->created_by,
        ]);

        // 3. Create Credit Entry (AP)
        JournalEntryItem::create([
            'entry_id' => $journalEntry->id,
            'account_id' => $apAccount->id,
            'description' => 'Accounts Payable for Bill #' . $bill->bill_number,
            'debit' => 0,
            'credit' => $bill->total_amount,
        ]);

        // 4. Create Debit Entries (Inventory or Expense)
        foreach ($bill->items as $item) {
            $debitAccount = $inventoryAccount; // Default to inventory
            
            if ($item->expense_account_id) {
                $debitAccount = ChartOfAccount::find($item->expense_account_id) ?? $inventoryAccount;
            }

            JournalEntryItem::create([
                'entry_id' => $journalEntry->id,
                'account_id' => $debitAccount->id,
                'description' => $item->description,
                'debit' => $item->total_price,
                'credit' => 0,
            ]);
        }

        // 5. Update Bill Status
        $bill->update(['status' => 'POSTED']);

        return $journalEntry;
    }

    /**
     * Post Maintenance Material Cost (COGS)
     */
    public function postMaintenanceCost(MaintenanceRecord $record)
    {
        if ($record->cost <= 0) return null;

        $inventoryAccount = $this->getOrInitAccount('1200', 'Inventory Asset', 'ASSET', 'DEBIT');
        $cogsAccount = $this->getOrInitAccount('5000', 'Cost of Goods Sold (Maintenance)', 'EXPENSE', 'DEBIT');

        $entryNumber = 'JE-COGS-' . date('Ymd') . '-' . strtoupper(Str::random(4));

        $journalEntry = JournalEntry::create([
            'entry_number' => $entryNumber,
            'date' => now(), // Usage date
            'description' => "Material Usage for Maintenance #{$record->id} - Vehicle: " . ($record->vehicle->name ?? 'N/A'),
            'reference' => 'MAINT-' . $record->id,
            'total_debit' => $record->cost,
            'total_credit' => $record->cost,
            'status' => 'POSTED',
            'created_by' => auth()->id(),
        ]);

        // Debit COGS (Expense increases with Debit)
        JournalEntryItem::create([
            'entry_id' => $journalEntry->id,
            'account_id' => $cogsAccount->id,
            'description' => 'Maintenance Material Cost',
            'debit' => $record->cost,
            'credit' => 0,
        ]);

        // Credit Inventory (Asset decreases with Credit)
        JournalEntryItem::create([
            'entry_id' => $journalEntry->id,
            'account_id' => $inventoryAccount->id,
            'description' => 'Inventory Deduction',
            'debit' => 0,
            'credit' => $record->cost,
        ]);

        return $journalEntry;
    }

    /**
     * Post Payroll Record
     */
    public function postPayrollRecord(PayrollRecord $record)
    {
        $salaryExpenseAccount = $this->getOrInitAccount('6000', 'Salaries Expense', 'EXPENSE', 'DEBIT');
        
        // If paid, credit Cash. If pending, credit Salaries Payable.
        if ($record->status === 'PAID') {
            $creditAccount = $this->getOrInitAccount('1001', 'Cash on Hand', 'ASSET', 'DEBIT'); // or Bank
        } else {
            $creditAccount = $this->getOrInitAccount('2200', 'Salaries Payable', 'LIABILITY', 'CREDIT');
        }

        $entryNumber = 'JE-PAY-' . date('Ymd') . '-' . strtoupper(Str::random(4));

        $journalEntry = JournalEntry::create([
            'entry_number' => $entryNumber,
            'date' => $record->paid_date ?? now(),
            'description' => "Payroll for {$record->user->name} - Period: {$record->period}",
            'reference' => 'PAY-' . $record->id,
            'total_debit' => $record->net_salary,
            'total_credit' => $record->net_salary,
            'status' => 'POSTED',
            'created_by' => auth()->id(),
        ]);

        // Debit Salaries Expense
        JournalEntryItem::create([
            'entry_id' => $journalEntry->id,
            'account_id' => $salaryExpenseAccount->id,
            'description' => "Salary Expense - {$record->user->name}",
            'debit' => $record->net_salary,
            'credit' => 0,
        ]);

        // Credit Cash/Payable
        JournalEntryItem::create([
            'entry_id' => $journalEntry->id,
            'account_id' => $creditAccount->id,
            'description' => "Payroll Liability/Payment - {$record->user->name}",
            'debit' => 0,
            'credit' => $record->net_salary,
        ]);

        return $journalEntry;
    }

    private function getOrInitAccount($code, $name, $type, $normalBalance)
    {
        return ChartOfAccount::firstOrCreate(
            ['code' => $code],
            [
                'name' => $name,
                'type' => $type,
                'normal_balance' => $normalBalance,
                'is_active' => true,
            ]
        );
    }
}
