<?php

namespace App\Domain\Financial\Services;

use App\Domain\Financial\Enums\TransactionType;
use App\Domain\Financial\Models\Expense;
use App\Domain\Financial\Models\FacilityRentPayment;
use App\Domain\Financial\Models\FinancialAccount;
use App\Domain\Financial\Models\Transaction;
use App\Domain\Shared\Exceptions\DomainException;
use App\Models\User;
use Illuminate\Support\Facades\DB;

class ExpenseService
{
    public function recordRentPayment(array $data, User $actor): FacilityRentPayment
    {
        return DB::transaction(function () use ($data, $actor) {
            $academyId = app('current_academy')?->id ?? $actor->academy_id;

            $rentPayment = FacilityRentPayment::create([
                'academy_id' => $academyId,
                'branch_id' => $data['branch_id'] ?? null,
                'facility_id' => $data['facility_id'],
                'period' => $data['period'],
                'amount' => $data['amount'],
                'payment_method' => $data['payment_method'],
                'cheque_number' => $data['cheque_number'] ?? null,
                'cheque_date' => $data['cheque_date'] ?? null,
                'bank_name' => $data['bank_name'] ?? null,
                'recipient_name' => $data['recipient_name'] ?? null,
                'payment_date' => $data['payment_date'],
                'notes' => $data['notes'] ?? null,
                'created_by' => $actor->id,
            ]);

            $this->createExpenseTransaction(
                academyId: $academyId,
                expenseAccountCode: '5010',
                paymentMethod: $data['payment_method'],
                amount: $data['amount'],
                description: "إيجار منشأة: {$data['period']}",
                referenceModel: $rentPayment,
                actor: $actor,
                transactionDate: $data['payment_date'],
            );

            return $rentPayment;
        });
    }

    public function recordExpense(array $data, User $actor): Expense
    {
        return DB::transaction(function () use ($data, $actor) {
            $academyId = app('current_academy')?->id ?? $actor->academy_id;

            $expense = Expense::create([
                'academy_id' => $academyId,
                'branch_id' => $data['branch_id'] ?? null,
                'category' => $data['category'],
                'amount' => $data['amount'],
                'description' => $data['description'],
                'recipient_name' => $data['recipient_name'] ?? null,
                'payment_method' => $data['payment_method'],
                'receipt_reference' => $data['receipt_reference'] ?? null,
                'expense_date' => $data['expense_date'],
                'notes' => $data['notes'] ?? null,
                'created_by' => $actor->id,
            ]);

            $expenseAccountCode = $this->resolveExpenseAccountCode($data['category']);

            $this->createExpenseTransaction(
                academyId: $academyId,
                expenseAccountCode: $expenseAccountCode,
                paymentMethod: $data['payment_method'],
                amount: $data['amount'],
                description: $data['description'],
                referenceModel: $expense,
                actor: $actor,
                transactionDate: $data['expense_date'],
            );

            return $expense;
        });
    }

    private function createExpenseTransaction(
        int $academyId,
        string $expenseAccountCode,
        string $paymentMethod,
        int $amount,
        string $description,
        $referenceModel,
        User $actor,
        string $transactionDate,
    ): void {
        $debitAccount = FinancialAccount::where('academy_id', $academyId)
            ->where('code', $expenseAccountCode)
            ->first();

        if (!$debitAccount) {
            throw new DomainException('حساب المصروفات غير موجود — يرجى إعداد شجرة الحسابات');
        }

        $creditAccountCode = match ($paymentMethod) {
            'cash' => '1000',
            'bank_transfer', 'cheque' => '1010',
            default => '1000',
        };

        $creditAccount = FinancialAccount::where('academy_id', $academyId)
            ->where('code', $creditAccountCode)
            ->first();

        if (!$creditAccount) {
            throw new DomainException('حساب النقدية/البنك غير موجود — يرجى إعداد شجرة الحسابات');
        }

        Transaction::create([
            'academy_id' => $academyId,
            'debit_account_id' => $debitAccount->id,
            'credit_account_id' => $creditAccount->id,
            'reference_type' => get_class($referenceModel),
            'reference_id' => $referenceModel->id,
            'amount' => $amount,
            'currency' => 'EGP',
            'type' => TransactionType::PaymentMade,
            'description' => $description,
            'transaction_date' => $transactionDate,
            'created_by' => $actor->id,
        ]);
    }

    private function resolveExpenseAccountCode(string $category): string
    {
        return match ($category) {
            'maintenance' => '5030',
            'utilities' => '5030',
            'sports_equipment' => '5020',
            'supplies' => '5020',
            default => '5050',
        };
    }
}
