<?php
namespace App\Services;

use App\Models\CommissionRule;
use App\Repositories\CommissionRuleRepository;
use App\Repositories\CommissionLedgerRepository;
use App\Utils\Logger;

class CommissionService
{
    private $ruleRepo;
    private $ledgerRepo;

    public function __construct(
        CommissionRuleRepository $ruleRepo,
        CommissionLedgerRepository $ledgerRepo
    ) {
        $this->ruleRepo = $ruleRepo;
        $this->ledgerRepo = $ledgerRepo;
    }

    public function getRules(array $filters = []): array
    {
        return $this->ruleRepo->getAll($filters);
    }

    public function saveRule(array $data): int
    {
        $kpiSource = trim((string)($data['kpi_source'] ?? ''));
        $targetUsersRaw = $data['target_users'] ?? [];
        $min = (float)($data['kpi_min_threshold'] ?? 0);
        $max = (float)($data['kpi_max_threshold'] ?? 0);
        $baseAmount = (float)($data['base_amount'] ?? 0);
        $rewardPercentage = (float)($data['reward_percentage'] ?? 0);
        $status = trim((string)($data['status'] ?? 'active'));
        $requestedServicesRaw = $data['requested_services'] ?? [];
        $tiersRaw = $data['tiers'] ?? '[]';

        if ($kpiSource === '') {
            throw new \InvalidArgumentException('منبع KPI الزامی است');
        }
        if ($max <= $min) {
            throw new \InvalidArgumentException('حداکثر آستانه باید از حداقل بزرگ‌تر باشد');
        }
        if ($rewardPercentage <= 0 || $rewardPercentage > 100) {
            throw new \InvalidArgumentException('درصد پاداش باید بین 1 تا 100 باشد');
        }

        if (is_string($targetUsersRaw)) {
            $decoded = json_decode($targetUsersRaw, true);
            $targetUsers = is_array($decoded) ? $decoded : [];
        } elseif (is_array($targetUsersRaw)) {
            $targetUsers = $targetUsersRaw;
        } else {
            $targetUsers = [];
        }
        if (empty($targetUsers)) {
            $targetUsers = ['ALL'];
        }
        if (is_string($requestedServicesRaw)) {
            $decodedServices = json_decode($requestedServicesRaw, true);
            $requestedServices = is_array($decodedServices) ? $decodedServices : [];
        } else {
            $requestedServices = is_array($requestedServicesRaw) ? $requestedServicesRaw : [];
        }
        if (empty($requestedServices)) {
            $requestedServices = ['ALL'];
        }

        if (is_string($tiersRaw)) {
            $decodedTiers = json_decode($tiersRaw, true);
            $tiers = is_array($decodedTiers) ? $decodedTiers : [];
        } else {
            $tiers = is_array($tiersRaw) ? $tiersRaw : [];
        }

        $rule = new CommissionRule([
            'id' => isset($data['id']) ? (int)$data['id'] : null,
            'kpi_source' => $kpiSource,
            'target_users' => $targetUsers,
            'requested_services' => $requestedServices,
            'kpi_min_threshold' => $min,
            'kpi_max_threshold' => $max,
            'base_amount' => $baseAmount,
            'reward_percentage' => $rewardPercentage,
            'status' => in_array($status, ['active', 'inactive'], true) ? $status : 'active',
        ]);
        $ruleId = $this->ruleRepo->save($rule);
        $this->saveRuleTiers($ruleId, $tiers);
        return $ruleId;
    }

    public function evaluateUserCommissions(int $userId, float $kpiScore, string $kpiSource): array
    {
        if ($userId <= 0) {
            throw new \InvalidArgumentException('شناسه کاربر نامعتبر است');
        }
        $kpiSource = trim($kpiSource);
        if ($kpiSource === '') {
            throw new \InvalidArgumentException('منبع KPI الزامی است');
        }

        $pdo = $this->ledgerRepo->getDb()->getPdo();
        $rules = $this->ruleRepo->findActiveByKpiSource($kpiSource);
        $results = [];

        try {
            $pdo->beginTransaction();
            foreach ($rules as $rule) {
                $targets = $rule->getTargetUsersArray();
                $appliesToAll = in_array('ALL', $targets, true);
                $appliesToUser = in_array($userId, array_map('intval', $targets), true);
                if (!$appliesToAll && !$appliesToUser) {
                    continue;
                }

                $min = (float)$rule->kpi_min_threshold;
                $max = (float)$rule->kpi_max_threshold;
                if ($kpiScore < $min || $kpiScore > $max) {
                    continue;
                }

                $baseAmount = (float)$rule->base_amount;
                $rewardPercentage = (float)$rule->reward_percentage;
                $finalAmount = round($baseAmount * ($rewardPercentage / 100), 2);

                $ledgerId = $this->ledgerRepo->store([
                    'user_id' => $userId,
                    'rule_id' => (int)$rule->id,
                    'kpi_score_recorded' => $kpiScore,
                    'calculated_amount' => $finalAmount,
                    'calculation_date' => date('Y-m-d H:i:s'),
                ]);

                $results[] = [
                    'ledger_id' => $ledgerId,
                    'rule_id' => (int)$rule->id,
                    'rule_title' => (string)$rule->title,
                    'kpi_score_recorded' => $kpiScore,
                    'calculated_amount' => $finalAmount,
                ];
            }
            $pdo->commit();
            return $results;
        } catch (\Throwable $e) {
            if ($pdo->inTransaction()) {
                $pdo->rollBack();
            }
            Logger::logError('COMMISSION_EVALUATION_FAILED', $e, [
                'user_id' => $userId,
                'kpi_source' => $kpiSource,
                'kpi_score' => $kpiScore,
            ]);
            throw $e;
        }
    }

    public function getUserLedger(int $userId): array
    {
        return $this->ledgerRepo->getByUser($userId);
    }

    private function saveRuleTiers(int $ruleId, array $tiers): void
    {
        if ($ruleId <= 0) {
            return;
        }
        $pdo = $this->ruleRepo->getDb()->getPdo();
        $pdo->beginTransaction();
        try {
            $pdo->prepare("DELETE FROM commission_rule_tiers WHERE rule_id = ?")->execute([$ruleId]);
            foreach ($tiers as $tier) {
                $min = isset($tier['min_realization']) ? (float)$tier['min_realization'] : null;
                $max = isset($tier['max_realization']) ? (float)$tier['max_realization'] : null;
                $commission = isset($tier['commission_percent']) ? (float)$tier['commission_percent'] : null;
                if ($min === null || $max === null || $commission === null) {
                    continue;
                }
                $stmt = $pdo->prepare("
                    INSERT INTO commission_rule_tiers
                        (rule_id, min_realization_percent, max_realization_percent, allocated_commission_percent)
                    VALUES (?, ?, ?, ?)
                ");
                $stmt->execute([$ruleId, $min, $max, $commission]);
            }
            $pdo->commit();
        } catch (\Throwable $e) {
            if ($pdo->inTransaction()) {
                $pdo->rollBack();
            }
            throw $e;
        }
    }

    // Compatibility no-op methods to avoid breaking existing call sites during migration window.
    public function calculateAndStoreForWonDeal(string $dealDidarId)
    {
        return null;
    }

    public function calculateAndCreateForDeal(string $dealDidarId)
    {
        return null;
    }
}
