<?php
namespace App\Controllers;

use App\Repositories\AccessRequestRepository;
use App\Repositories\PersonRepository;
use App\Utils\Sanitizer;

/**
 * Customer access requests — a lightweight ticketing flow.
 * Sales experts (agent) create requests from a lead card; support resolves them
 * from a dedicated inbox. RBAC: customer_access.create / .view / .resolve.
 */
class AccessRequestController extends ApiController
{
    private $accessRepo;
    private $personRepo;

    public function __construct(AccessRequestRepository $accessRepo, PersonRepository $personRepo)
    {
        $this->accessRepo = $accessRepo;
        $this->personRepo = $personRepo;
    }

    private function canRbac(string $cap): bool
    {
        global $app;
        return isset($app->services->rbac) && $app->services->rbac
            ? (bool)$app->services->rbac->can($cap)
            : false;
    }

    private function requireRbac(string $cap, string $message): void
    {
        if (!$this->canRbac($cap)) {
            $this->errorResponse($message, 403);
        }
    }

    private function sessionDidarId(): string
    {
        return trim((string)($_SESSION['didar_id'] ?? ''));
    }

    private function userNameByDidarId(string $didarId): string
    {
        $didarId = trim($didarId);
        if ($didarId === '') {
            return '';
        }
        global $app;
        $db = $app->db;
        $field = $db->hasColumn('users', 'display_name')
            ? 'display_name'
            : "CONCAT(first_name, ' ', last_name)";
        $stmt = $db->getPdo()->prepare("SELECT $field FROM users WHERE didar_user_id = ? LIMIT 1");
        $stmt->execute([$didarId]);
        return trim((string)($stmt->fetchColumn() ?: ''));
    }

    public function create(): void
    {
        $this->requireRbac('customer_access.create', 'دسترسی به ثبت درخواست دسترسی مشتری ندارید');

        $contactId = Sanitizer::sanitize($_POST['contact_id'] ?? '');
        $requestType = Sanitizer::sanitize($_POST['request_type'] ?? 'grant');
        $dealId = (int)($_POST['deal_id'] ?? 0);
        $phone = Sanitizer::sanitize($_POST['selected_phone'] ?? '');
        $description = Sanitizer::sanitize($_POST['description'] ?? '');

        if ($contactId === '') {
            $this->errorResponse('شناسه مشتری الزامی است');
        }
        if (!in_array($requestType, ['grant', 'revoke'], true)) {
            $this->errorResponse('نوع درخواست نامعتبر است');
        }
        $person = $this->personRepo->findByDidarId($contactId);
        if (!$person) {
            $this->errorResponse('مشتری یافت نشد');
        }
        if ($dealId <= 0) {
            $this->errorResponse('انتخاب معامله الزامی است');
        }
        if ($phone === '') {
            $this->errorResponse('انتخاب شماره تلفن الزامی است');
        }
        if ($description === '') {
            $this->errorResponse('توضیحات الزامی است');
        }

        // Load the chosen deal and confirm it belongs to this customer.
        global $app;
        $stmt = $app->db->getPdo()->prepare("SELECT id, didar_deal_id, title, owner_didar_id, contact_didar_id FROM deals WHERE id = ? LIMIT 1");
        $stmt->execute([$dealId]);
        $deal = $stmt->fetch(\PDO::FETCH_ASSOC);
        if (!$deal || trim((string)$deal['contact_didar_id']) !== trim((string)$person->didar_contact_id)) {
            $this->errorResponse('معامله انتخابی متعلق به این مشتری نیست');
        }

        $ownerDidar = trim((string)($deal['owner_didar_id'] ?? ''));
        $data = [
            'contact_didar_id' => $person->didar_contact_id,
            'request_type' => $requestType,
            'deal_id' => $dealId,
            'deal_didar_id' => $deal['didar_deal_id'] ?? null,
            'deal_title' => $deal['title'] ?? null,
            'product_type' => $this->accessRepo->dealProductType($dealId),
            'selected_phone' => $phone,
            'deal_owner_didar_id' => $ownerDidar ?: null,
            'deal_owner_name' => $this->userNameByDidarId($ownerDidar),
            'description' => $description,
            'requested_by_didar_id' => $this->sessionDidarId(),
            'requested_by_name' => trim((string)($_SESSION['name'] ?? '')) ?: $this->userNameByDidarId($this->sessionDidarId()),
        ];
        $id = $this->accessRepo->create($data);

        $this->notifySupport($id, $person, $data);
        $this->successResponse(['id' => $id], 'درخواست دسترسی برای پشتیبانی ارسال شد');
    }

    public function getForContact(): void
    {
        $this->requireRbac('customer_access.view', 'دسترسی به مشاهده درخواست‌های دسترسی ندارید');
        $contactId = Sanitizer::sanitize($_POST['contact_id'] ?? '');
        if ($contactId === '') {
            $this->errorResponse('شناسه مشتری الزامی است');
        }
        // Support/admin (resolve capability) see all requests on this lead; others see only their own.
        $scope = $this->canRbac('customer_access.resolve') ? null : $this->sessionDidarId();
        $requests = $this->accessRepo->getByContact($contactId, $scope);
        $this->successResponse(['requests' => $requests]);
    }

    public function getInbox(): void
    {
        $this->requireRbac('customer_access.resolve', 'دسترسی به صف درخواست‌های پشتیبانی ندارید');
        $status = Sanitizer::sanitize($_POST['status'] ?? '');
        $requests = $this->accessRepo->getInbox($status);
        $this->successResponse(['requests' => $requests]);
    }

    public function setStatus(): void
    {
        $this->requireRbac('customer_access.resolve', 'دسترسی به تغییر وضعیت درخواست ندارید');
        $id = (int)($_POST['id'] ?? 0);
        $status = Sanitizer::sanitize($_POST['status'] ?? '');
        $note = Sanitizer::sanitize($_POST['resolution_note'] ?? '');
        if ($id <= 0) {
            $this->errorResponse('شناسه درخواست نامعتبر است');
        }
        if (!in_array($status, ['pending', 'done', 'not_done'], true)) {
            $this->errorResponse('وضعیت نامعتبر است');
        }
        // رد کردن درخواست نیازمند ثبت علت است.
        if ($status === 'not_done' && $note === '') {
            $this->errorResponse('برای رد درخواست، ثبت علت الزامی است');
        }
        $row = $this->accessRepo->findById($id);
        if (!$row) {
            $this->errorResponse('درخواست یافت نشد');
        }
        // درخواست تنها یک‌بار قابل اعمال وضعیت است؛ پس از تأیید/رد دیگر تغییرپذیر نیست.
        if (($row['status'] ?? 'pending') !== 'pending') {
            $this->errorResponse('این درخواست قبلاً بررسی شده و قابل تغییر نیست');
        }
        $this->accessRepo->updateStatus($id, $status, $this->sessionDidarId(), $note);
        $this->notifyRequester($row, $status, $note);
        $this->successResponse([], 'وضعیت درخواست به‌روزرسانی شد');
    }

    private function statusLabel(string $status): string
    {
        return ['pending' => 'در انتظار', 'done' => 'انجام‌شده', 'not_done' => 'انجام‌نشده'][$status] ?? $status;
    }

    private function requestTypeLabel(string $type): string
    {
        return ['grant' => 'افزودن دسترسی', 'revoke' => 'حذف دسترسی'][$type] ?? 'افزودن دسترسی';
    }

    private function notifySupport(int $id, $person, array $data): void
    {
        global $app;
        if (!isset($app->services->notification) || !$app->services->notification) {
            return;
        }
        $customer = trim((string)($person->first_name ?? '') . ' ' . (string)($person->last_name ?? '')) ?: 'مشتری';
        $title = 'درخواست دسترسی مشتری جدید';
        $message = sprintf(
            'درخواست «%s» برای «%s» توسط %s ثبت شد.',
            $this->requestTypeLabel((string)($data['request_type'] ?? 'grant')),
            $customer,
            $data['requested_by_name'] ?: 'کارشناس فروش'
        );
        try {
            $stmt = $app->db->getPdo()->query("SELECT didar_user_id FROM users WHERE role = 'support' AND is_active = 1");
            foreach ($stmt->fetchAll(\PDO::FETCH_COLUMN) as $didar) {
                if (trim((string)$didar) !== '') {
                    $app->services->notification->create($didar, 'customer_access', $title, $message, 'customer_access_request', (string)$id);
                }
            }
        } catch (\Throwable $e) {
            // notifications are best-effort
        }
    }

    private function notifyRequester(array $row, string $status, string $note = ''): void
    {
        global $app;
        if (!isset($app->services->notification) || !$app->services->notification) {
            return;
        }
        $requester = trim((string)($row['requested_by_didar_id'] ?? ''));
        if ($requester === '') {
            return;
        }
        $title = 'به‌روزرسانی درخواست دسترسی مشتری';
        $message = sprintf('وضعیت درخواست شما به «%s» تغییر کرد.', $this->statusLabel($status));
        if ($status === 'not_done' && $note !== '') {
            $message .= ' علت رد: ' . $note;
        }
        try {
            $app->services->notification->create($requester, 'customer_access', $title, $message, 'customer_access_request', (string)($row['id'] ?? ''));
        } catch (\Throwable $e) {
            // best-effort
        }
    }
}
