<?php

declare(strict_types=1);

namespace ImovelZapAi\Financial\Application\Actions;

use Illuminate\Support\Facades\DB;
use ImovelZapAi\Financial\Domain\Enums\BeneficiaryType;
use ImovelZapAi\Financial\Domain\Enums\CommissionBasis;
use ImovelZapAi\Financial\Domain\Enums\CommissionStatus;
use ImovelZapAi\Financial\Domain\Enums\SplitStatus;
use ImovelZapAi\Financial\Domain\Events\CommissionCalculated;
use ImovelZapAi\Financial\Infrastructure\Persistence\Eloquent\FinancialCommissionModel;
use ImovelZapAi\Financial\Infrastructure\Persistence\Eloquent\FinancialCommissionRuleModel;
use ImovelZapAi\Financial\Infrastructure\Persistence\Eloquent\FinancialCommissionSplitModel;
use ImovelZapAi\Sales\Infrastructure\Persistence\Eloquent\DealModel;

final class CalculateCommissionAction
{
    public function execute(
        string $tenantId,
        DealModel $deal,
        FinancialCommissionRuleModel $rule,
    ): FinancialCommissionModel {
        return DB::transaction(function () use ($tenantId, $deal, $rule): FinancialCommissionModel {
            $baseAmount = (float) ($deal->amount ?? 0);
            $totalAmount = $rule->basis === CommissionBasis::Percent
                ? round($baseAmount * ((float) $rule->value / 100), 2)
                : round((float) $rule->value, 2);

            $commission = FinancialCommissionModel::query()->create([
                'tenant_id' => $tenantId,
                'deal_id' => $deal->id,
                'rule_id' => $rule->id,
                'base_amount' => $baseAmount,
                'total_amount' => $totalAmount,
                'status' => CommissionStatus::Calculated,
                'calculated_at' => now(),
            ]);

            $splitDefinitions = $this->resolveSplits($deal, $rule);

            foreach ($splitDefinitions as $split) {
                $amount = round($totalAmount * ($split['percent'] / 100), 2);
                FinancialCommissionSplitModel::query()->create([
                    'tenant_id' => $tenantId,
                    'commission_id' => $commission->id,
                    'beneficiary_type' => $split['type'],
                    'beneficiary_user_id' => $split['user_id'] ?? null,
                    'beneficiary_label' => $split['label'],
                    'percent' => $split['percent'],
                    'amount' => $amount,
                    'status' => SplitStatus::Pending,
                ]);
            }

            CommissionCalculated::dispatch($tenantId, (string) $commission->id);

            return $commission->load('splits');
        });
    }

    /**
     * @return list<array{type: BeneficiaryType, user_id?: int|null, label: string, percent: float}>
     */
    private function resolveSplits(DealModel $deal, FinancialCommissionRuleModel $rule): array
    {
        if (is_array($rule->split_json) && $rule->split_json !== []) {
            $splits = [];
            foreach ($rule->split_json as $item) {
                $type = BeneficiaryType::tryFrom((string) ($item['type'] ?? 'agency')) ?? BeneficiaryType::Agency;
                $splits[] = [
                    'type' => $type,
                    'user_id' => $item['user_id'] ?? null,
                    'label' => (string) ($item['label'] ?? $type->label()),
                    'percent' => (float) ($item['percent'] ?? 0),
                ];
            }

            return $splits;
        }

        if ($deal->responsible_user_id !== null) {
            return [
                [
                    'type' => BeneficiaryType::Agency,
                    'label' => 'Imobiliária',
                    'percent' => 50.0,
                ],
                [
                    'type' => BeneficiaryType::User,
                    'user_id' => $deal->responsible_user_id,
                    'label' => 'Corretor responsável',
                    'percent' => 50.0,
                ],
            ];
        }

        return [
            [
                'type' => BeneficiaryType::Agency,
                'label' => 'Imobiliária',
                'percent' => 100.0,
            ],
        ];
    }
}
