<?php
namespace App\Controllers;

use App\Services\CommissionService;
use App\Services\AuthService;
use App\Repositories\UserRepository;
use App\Controllers\Concerns\BulkDeleteRequest;
use App\Utils\Sanitizer;
use App\Utils\Logger;

class CommissionController extends ApiController
{
    use BulkDeleteRequest;

    private $commissionService;
    private $authService;
    private $userRepo;

    public function __construct(
        CommissionService $commissionService,
        AuthService $authService,
        UserRepository $userRepo
    ) {
        $this->commissionService = $commissionService;
        $this->authService = $authService;
        $this->userRepo = $userRepo;
    }

    public function getRules()
    {
        $selfOnly = (($_SESSION['role'] ?? '') === 'agent') && !$this->authService->isAdminOrCrmSpecialist();
        if (!$selfOnly) {
            $this->assertAdminOrCrm();
        }
        $rules = array_map(function ($rule) use ($selfOnly) {
            $payload = $rule->toArray();
            $ruleTypeRaw = strtoupper(trim((string)($payload['rule_type'] ?? '')));
            if ($ruleTypeRaw === '') {
                $legacyType = strtoupper(trim((string)($payload['type'] ?? '')));
                if ($legacyType !== '') {
                    $ruleTypeRaw = $legacyType;
                }
            }
            if ($ruleTypeRaw === '') {
                $kpiSource = strtolower(trim((string)($payload['kpi_source'] ?? $payload['kpi_key'] ?? '')));
                $ruleTypeRaw = ($kpiSource !== '' && $kpiSource !== 'tiered_cashflow')
                    ? 'KPI_NUMERICAL'
                    : 'TIERED_CASHFLOW';
            }
            $payload['rule_type'] = $ruleTypeRaw;
            if ($selfOnly) {
                $payload['target_users'] = [];
            }
            $salespersonId = (int)($payload['salesperson_user_id'] ?? 0);
            if ($salespersonId > 0) {
                $u = $this->userRepo->findById($salespersonId);
                if ($u) {
                    $payload['salesperson'] = [
                        'id' => (int)$u->id,
                        'first_name' => (string)($u->first_name ?? ''),
                        'last_name' => (string)($u->last_name ?? ''),
                        'display_name' => (string)($u->display_name ?? ''),
                        'role' => (string)($u->role ?? ''),
                    ];
                }
            } else {
                $payload['salesperson'] = null;
            }
            $payload['tiers'] = $this->commissionService->getRuleTiers((int)($payload['id'] ?? 0));
            return $payload;
        }, $this->commissionService->getRules());
        $this->successResponse(['rules' => $rules]);
    }

    public function getMyLedger()
    {
        if (!$this->authService->isAuthenticated()) {
            $this->errorResponse('دسترسی محدود', 403);
        }
        $userId = (int)($_SESSION['user_id'] ?? 0);
        if ($userId <= 0) {
            $this->errorResponse('کاربر معتبر نیست', 422);
        }
        $rows = array_map(static function ($row) {
            return $row->toArray();
        }, $this->commissionService->getUserLedger($userId));
        $this->successResponse(['ledger' => $rows]);
    }

    public function storeRule()
    {
        $this->assertAdminOrCrm();
        error_log('[store_commission_rule] payload=' . print_r($_POST, true));

        $targetUsers = $_POST['target_users'] ?? '[]';
        $salespersonRaw = $_POST['salesperson_user_id'] ?? null;
        $salespersonId = null;
        if ($salespersonRaw !== null && $salespersonRaw !== '') {
            $salespersonId = (int)$salespersonRaw;
            if ($salespersonId <= 0) {
                $salespersonId = null;
            }
        }
        $payload = [
            'id' => (int)($_POST['id'] ?? 0),
            'rule_type' => Sanitizer::sanitize($_POST['rule_type'] ?? 'TIERED_CASHFLOW'),
            'kpi_source' => Sanitizer::sanitize($_POST['kpi_source'] ?? ''),
            'target_users' => $targetUsers,
            'salesperson_user_id' => $salespersonId,
            'valid_from' => Sanitizer::sanitize($_POST['valid_from'] ?? ''),
            'valid_to' => Sanitizer::sanitize($_POST['valid_to'] ?? ''),
            'requested_services' => $_POST['requested_services'] ?? '[]',
            'kpi_min_threshold' => (float)($_POST['kpi_min_threshold'] ?? 0),
            'kpi_max_threshold' => (float)($_POST['kpi_max_threshold'] ?? 0),
            'base_amount' => (float)($_POST['base_amount'] ?? 0),
            'reward_percentage' => (float)($_POST['reward_percentage'] ?? 0),
            'status' => Sanitizer::sanitize($_POST['status'] ?? 'active'),
            'tiers' => $_POST['tiers'] ?? '[]',
        ];

        if ($payload['kpi_max_threshold'] <= $payload['kpi_min_threshold']) {
            $this->errorResponse('حداکثر آستانه باید از حداقل بزرگ‌تر باشد', 422);
        }
        if ($payload['reward_percentage'] < 0 || $payload['reward_percentage'] > 100) {
            $this->errorResponse('درصد پاداش باید بین 0 تا 100 باشد', 422);
        }

        if ($salespersonId !== null && !$this->userRepo->findById($salespersonId)) {
            $this->errorResponse('کاربر انتخاب شده نامعتبر است', 422);
        }

        $decodedTargets = json_decode((string)$targetUsers, true);
        $targetIds = is_array($decodedTargets) ? $decodedTargets : [];
        if ($salespersonId !== null) {
            $targetIds = [$salespersonId];
            $payload['target_users'] = json_encode([$salespersonId], JSON_UNESCAPED_UNICODE);
        }
        $numericTargets = array_values(array_filter(array_map('intval', $targetIds), static function ($id) {
            return $id > 0;
        }));
        foreach ($numericTargets as $targetId) {
            if (!$this->userRepo->findById($targetId)) {
                $this->errorResponse('کاربر انتخاب شده نامعتبر است', 422);
            }
        }

        try {
            $id = $this->commissionService->saveRule($payload);
            $this->successResponse(['id' => $id], 'قانون کمیسیون ذخیره شد');
        } catch (\PDOException $e) {
            $message = (string)$e->getMessage();
            error_log('[store_commission_rule][pdo_exception] ' . $message);
            Logger::logError('STORE_COMMISSION_RULE_PDO', $e, ['post' => $_POST]);
            $isFkViolation = strpos($message, 'Integrity constraint violation') !== false
                || strpos($message, 'SQLSTATE[23000]') !== false;
            $isSalespersonFk = strpos($message, 'commission_rules_ibfk_1') !== false
                || strpos($message, 'salesperson_user_id') !== false;
            $isProductFk = strpos($message, 'commission_rules_ibfk_2') !== false
                || strpos($message, 'product_id') !== false;
            if ($isFkViolation && $isSalespersonFk) {
                $this->errorResponse('کاربر انتخاب شده نامعتبر است', 422);
            }
            if ($isFkViolation && $isProductFk) {
                $this->errorResponse('محصول انتخاب شده نامعتبر است', 422);
            }
            $this->errorResponse('خطای پایگاه داده در ذخیره قانون پورسانت', 500);
        } catch (\InvalidArgumentException $e) {
            $this->errorResponse($e->getMessage(), 422);
        } catch (\Throwable $e) {
            Logger::logError('STORE_COMMISSION_RULE_UNKNOWN', $e, ['post' => $_POST]);
            $this->errorResponse('خطا در ذخیره قانون پورسانت', 500);
        }
    }

    public function evaluate()
    {
        $this->assertAdminOrCrm();

        $userId = (int)($_POST['user_id'] ?? 0);
        $kpiScore = (float)($_POST['kpi_score'] ?? 0);
        $kpiSource = Sanitizer::sanitize($_POST['kpi_source'] ?? '');
        if ($userId <= 0 || $kpiSource === '') {
            $this->errorResponse('کاربر، منبع KPI و امتیاز الزامی هستند', 422);
        }

        $result = $this->commissionService->evaluateUserCommissions($userId, $kpiScore, $kpiSource);
        $this->successResponse(['results' => $result]);
    }

    public function getDealCommissions()
    {
        $this->assertAdminOrCrm();
        $filters = [
            'status' => Sanitizer::sanitize($_POST['status'] ?? $_GET['status'] ?? ''),
            'salesperson_user_id' => (int)($_POST['salesperson_user_id'] ?? $_GET['salesperson_user_id'] ?? 0),
            'date_from' => Sanitizer::sanitize($_POST['date_from'] ?? $_GET['date_from'] ?? ''),
            'date_to' => Sanitizer::sanitize($_POST['date_to'] ?? $_GET['date_to'] ?? ''),
            'amount_min' => $_POST['amount_min'] ?? $_GET['amount_min'] ?? '',
            'amount_max' => $_POST['amount_max'] ?? $_GET['amount_max'] ?? '',
        ];
        $rows = $this->commissionService->getDealCommissions($filters);
        $this->successResponse(['commissions' => $rows]);
    }

    public function updateDealCommissionStatus()
    {
        $this->assertAdminOrCrm();
        $id = (int)($_POST['commission_id'] ?? 0);
        $status = Sanitizer::sanitize($_POST['status'] ?? '');
        $actorUserId = (int)($_SESSION['user_id'] ?? 0);
        if ($id <= 0 || $status === '') {
            $this->errorResponse('ورودی نامعتبر است', 422);
        }
        $ok = $this->commissionService->updateDealCommissionStatus($id, $status, $actorUserId);
        if (!$ok) {
            $this->errorResponse('به‌روزرسانی وضعیت انجام نشد', 500);
        }
        $this->successResponse([], 'وضعیت پورسانت به‌روزرسانی شد');
    }

    public function deleteDealCommission()
    {
        $this->assertAdminOrCrm();
        $id = (int)($_POST['commission_id'] ?? 0);
        if ($id <= 0) {
            $this->errorResponse('شناسه نامعتبر است', 422);
        }
        $role = trim((string)($_SESSION['role'] ?? ''));
        $actorUserId = (int)($_SESSION['user_id'] ?? 0);
        try {
            $this->commissionService->deleteDealCommission($id, $role, $actorUserId);
            $this->successResponse([], 'رکورد پورسانت حذف شد');
        } catch (\RuntimeException $e) {
            if ($e->getMessage() === 'FORBIDDEN_DELETE') {
                $this->errorResponse('شما مجاز به حذف این رکورد نیستید', 403);
            }
            $this->errorResponse($e->getMessage(), 422);
        } catch (\Throwable $e) {
            $this->errorResponse('خطا در حذف رکورد پورسانت', 500);
        }
    }

    public function bulkDeleteRules()
    {
        $this->assertAdminOrCrm();
        $role = trim((string)($_SESSION['role'] ?? ''));
        $ids = $this->parseBulkDeleteIds($_POST['ids'] ?? ($_POST['rule_ids'] ?? '[]'));
        if (count($ids) < 1) {
            $this->errorResponse('حداقل یک رکورد معتبر برای حذف گروهی لازم است', 422);
        }

        try {
            $pdo = $this->commissionService->getRuleRepository()->getDb()->getPdo();
            $validIds = $this->validateBulkDeleteIdsExist($pdo, 'commission_rules', $ids);
            if (count($validIds) < 1) {
                $this->errorResponse('شناسه‌های ارسالی معتبر نیستند', 422);
            }
            $result = $this->commissionService->deleteCommissionRulesBulk($validIds, $role);
            if (empty($result['deleted'])) {
                $this->errorResponse('هیچ قانونی حذف نشد', 422);
            }
            $this->successResponse($result, 'حذف گروهی قوانین انجام شد');
        } catch (\RuntimeException $e) {
            if ($e->getMessage() === 'FORBIDDEN_DELETE') {
                $this->errorResponse('دسترسی حذف گروهی ندارید', 403);
            }
            $this->errorResponse($e->getMessage(), 422);
        } catch (\Throwable $e) {
            $this->errorResponse('خطا در حذف گروهی قوانین', 500);
        }
    }

    public function deleteRule()
    {
        $this->assertAdminOrCrm();
        $id = (int)($_POST['rule_id'] ?? 0);
        if ($id <= 0) {
            $this->errorResponse('شناسه قانون نامعتبر است', 422);
        }
        $role = trim((string)($_SESSION['role'] ?? ''));
        try {
            $this->commissionService->deleteCommissionRule($id, $role);
            $this->successResponse([], 'قانون پورسانت حذف شد');
        } catch (\RuntimeException $e) {
            if ($e->getMessage() === 'FORBIDDEN_DELETE') {
                $this->errorResponse('شما مجاز به حذف این قانون نیستید', 403);
            }
            $this->errorResponse($e->getMessage(), 422);
        } catch (\Throwable $e) {
            $this->errorResponse('خطا در حذف قانون پورسانت', 500);
        }
    }

    public function bulkDeleteDealCommissions()
    {
        $this->assertAdminOrCrm();
        $ids = $this->parseBulkDeleteIds($_POST['ids'] ?? '[]');
        if (count($ids) < 1) {
            $this->errorResponse('حداقل یک رکورد معتبر برای حذف گروهی لازم است', 422);
        }

        $role = trim((string)($_SESSION['role'] ?? ''));
        $actorUserId = (int)($_SESSION['user_id'] ?? 0);
        $pdo = $this->commissionService->getRuleRepository()->getDb()->getPdo();
        $validIds = $this->validateBulkDeleteIdsExist($pdo, 'deal_commissions', $ids);
        if (count($validIds) < 1) {
            $this->errorResponse('شناسه‌های ارسالی معتبر نیستند', 422);
        }
        $deleted = [];
        $skipped = [];
        foreach ($validIds as $id) {
            $cid = (int)$id;
            if ($cid <= 0) {
                continue;
            }
            try {
                $this->commissionService->deleteDealCommission($cid, $role, $actorUserId);
                $deleted[] = $cid;
            } catch (\RuntimeException $e) {
                $skipped[] = ['id' => $cid, 'reason' => $e->getMessage()];
            } catch (\Throwable $e) {
                $skipped[] = ['id' => $cid, 'reason' => 'error'];
            }
        }
        $this->successResponse(['deleted' => $deleted, 'skipped' => $skipped], 'حذف گروهی رکوردهای پورسانت انجام شد');
    }

    public function getSetupData()
    {
        $selfOnly = (($_SESSION['role'] ?? '') === 'agent') && !$this->authService->isAdminOrCrmSpecialist();
        if (!$selfOnly) {
            $this->assertAdminOrCrm();
        }
        $allUsers = $this->userRepo->getAll();
        if ($selfOnly) {
            $currentId = (int)($_SESSION['user_id'] ?? 0);
            $allUsers = array_values(array_filter($allUsers, static function ($u) use ($currentId) {
                return (int)($u->id ?? 0) === $currentId;
            }));
        }
        $users = array_map(static function ($user) {
            return [
                'id' => (int)$user->id,
                'display_name' => trim((string)($user->display_name ?: ($user->first_name . ' ' . $user->last_name))),
                'is_active' => (int)$user->is_active,
                'role' => (string)$user->role,
            ];
        }, $allUsers);

        $this->successResponse([
            'users' => $users,
            'kpi_sources' => ['kpi_calls', 'kpi_meetings', 'kpi_sales_volume', 'kpi_followups'],
        ]);
    }

    private function assertAdminOrCrm(): void
    {
        if (!$this->authService->hasGlobalAdminOverride() && !$this->authService->isCrmSpecialist()) {
            $this->errorResponse('دسترسی محدود', 403);
        }
    }
}
