<?php
/**
 * UserAgreement Model
 * Maps to `user_agreements`, `agreement_history`, and `user_agreement_acceptances` tables
 */

require_once __DIR__ . '/../Core/Model.php';
require_once __DIR__ . '/../Helpers/Security.php';

class UserAgreement extends Model {
    protected string $table = 'user_agreements';

    public static array $types = [
        'customer' => 'Customer Terms & Conditions (ข้อกำหนดและเงื่อนไขการใช้งานสำหรับผู้ซื้อ)',
        'seller' => 'Seller Agreement (ข้อตกลงและเงื่อนไขสำหรับผู้ขาย)',
        'privacy_policy' => 'Privacy Policy (นโยบายความเป็นส่วนตัว)',
        'seller_commission' => 'Seller Commission Policy (นโยบายค่าธรรมเนียมและคอมมิชชัน)',
        'product_listing' => 'Product Listing Policy (นโยบายและมาตรฐานการลงขายสินค้า)',
        'return_refund' => 'Return & Refund Policy (นโยบายการคืนสินค้าและคืนเงิน)',
        'marketplace_rules' => 'Marketplace Rules (กฎและกติกากลางของตลาด)'
    ];

    /**
     * Get latest active version for a given policy type
     */
    public function getLatestActive(string $type = 'customer'): ?array {
        $sql = "SELECT * FROM `user_agreements` WHERE `type` = :type AND `status` = 'active' ORDER BY `id` DESC LIMIT 1";
        return $this->fetchOne($sql, [':type' => $type]);
    }

    /**
     * Get all currently active policies
     */
    public function getAllActivePolicies(): array {
        $sql = "SELECT * FROM `user_agreements` WHERE `status` = 'active' ORDER BY `type` ASC";
        return $this->fetchAll($sql);
    }

    /**
     * Get policy by type and optional specific version
     */
    public function getPolicyByTypeAndVersion(string $type, ?string $version = null): ?array {
        if ($version) {
            $sql = "SELECT * FROM `user_agreements` WHERE `type` = :type AND `version` = :ver LIMIT 1";
            return $this->fetchOne($sql, [':type' => $type, ':ver' => $version]);
        }
        return $this->getLatestActive($type);
    }

    /**
     * Get all historical versions of a policy type
     */
    public function getVersionsByType(string $type): array {
        $sql = "SELECT id, version, status, effective_date, created_at 
                FROM `user_agreements` 
                WHERE `type` = :type 
                ORDER BY `id` DESC";
        return $this->fetchAll($sql, [':type' => $type]);
    }

    /**
     * Admin: Get all policies with filtering
     */
    public function getAdminPolicies(array $filters = [], int $limit = 20, int $offset = 0): array {
        [$whereSql, $params] = $this->buildFilterConditions($filters);

        $sql = "SELECT ua.*, u.username as creator_username,
                (SELECT COUNT(*) FROM `user_agreement_acceptances` uaa WHERE uaa.agreement_id = ua.id) as acceptances_count
                FROM `user_agreements` ua
                LEFT JOIN `users` u ON ua.created_by = u.id
                WHERE {$whereSql}
                ORDER BY ua.type ASC, ua.id DESC
                LIMIT :limit OFFSET :offset";

        $stmt = $this->db->prepare($sql);
        foreach ($params as $k => $v) {
            $stmt->bindValue($k, $v);
        }
        $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
        $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
        $stmt->execute();

        return $stmt->fetchAll();
    }

    public function countAdminPolicies(array $filters = []): int {
        [$whereSql, $params] = $this->buildFilterConditions($filters);

        $sql = "SELECT COUNT(*) FROM `user_agreements` ua WHERE {$whereSql}";
        $stmt = $this->db->prepare($sql);
        foreach ($params as $k => $v) {
            $stmt->bindValue($k, $v);
        }
        $stmt->execute();

        return (int)$stmt->fetchColumn();
    }

    private function buildFilterConditions(array $filters): array {
        $conditions = ["1=1"];
        $params = [];

        if (!empty($filters['q'])) {
            $conditions[] = "(ua.title LIKE :kw OR ua.content LIKE :kw OR ua.version LIKE :kw)";
            $params[':kw'] = '%' . trim($filters['q']) . '%';
        }

        if (!empty($filters['type']) && $filters['type'] !== 'all') {
            $conditions[] = "ua.type = :type";
            $params[':type'] = $filters['type'];
        }

        if (!empty($filters['status']) && $filters['status'] !== 'all') {
            $conditions[] = "ua.status = :status";
            $params[':status'] = $filters['status'];
        }

        return [implode(" AND ", $conditions), $params];
    }

    /**
     * Create Draft Policy
     */
    public function createDraft(array $data, int $adminId): int {
        $data['status'] = 'draft';
        $data['created_by'] = $adminId;
        $data['created_at'] = date('Y-m-d H:i:s');
        $data['updated_at'] = date('Y-m-d H:i:s');

        $agreementId = $this->insert($data);
        $this->logHistory($agreementId, 'draft_created', $adminId, "Created draft version {$data['version']} for {$data['type']}");

        return $agreementId;
    }

    /**
     * Update Draft Policy (Only draft versions are editable!)
     */
    public function updateDraft(int $id, array $data, int $adminId): bool {
        $policy = $this->findById($id);
        if (!$policy || $policy['status'] !== 'draft') {
            return false; // Published/active versions are immutable
        }

        $data['updated_by'] = $adminId;
        $data['updated_at'] = date('Y-m-d H:i:s');

        $this->update($id, $data);
        $this->logHistory($id, 'draft_updated', $adminId, "Updated draft content for version {$policy['version']}");

        return true;
    }

    /**
     * Publish Policy (Archives previous active versions of this type)
     */
    public function publish(int $id, int $adminId): bool {
        $policy = $this->findById($id);
        if (!$policy) {
            return false;
        }

        $type = $policy['type'];

        $this->db->beginTransaction();
        try {
            // Archive previous active versions of this type
            $sqlArchive = "UPDATE `user_agreements` SET `status` = 'inactive', `updated_by` = :admin_id, `updated_at` = NOW() 
                           WHERE `type` = :type AND `status` = 'active' AND `id` != :id";
            $this->query($sqlArchive, [':admin_id' => $adminId, ':type' => $type, ':id' => $id]);

            // Set current to active with effective_date
            $sqlPublish = "UPDATE `user_agreements` SET `status` = 'active', `effective_date` = NOW(), `updated_by` = :admin_id, `updated_at` = NOW() 
                           WHERE `id` = :id";
            $this->query($sqlPublish, [':admin_id' => $adminId, ':id' => $id]);

            $this->logHistory($id, 'published', $adminId, "Published policy version {$policy['version']} (Previous versions archived)");

            $this->db->commit();
            return true;
        } catch (Exception $e) {
            $this->db->rollBack();
            throw $e;
        }
    }

    /**
     * Archive Policy
     */
    public function archive(int $id, int $adminId): bool {
        $policy = $this->findById($id);
        if (!$policy) {
            return false;
        }

        $this->update($id, [
            'status' => 'inactive',
            'updated_by' => $adminId,
            'updated_at' => date('Y-m-d H:i:s')
        ]);

        $this->logHistory($id, 'archived', $adminId, "Archived policy version {$policy['version']}");
        return true;
    }

    /**
     * Record User Acceptance
     */
    public function recordAcceptance(int $userId, int $agreementId, string $type, string $version): void {
        $sql = "INSERT INTO `user_agreement_acceptances` (`user_id`, `agreement_id`, `agreement_type`, `version`, `ip_address`, `user_agent`, `accepted_at`) 
                VALUES (:user_id, :agreement_id, :agreement_type, :version, :ip, :ua, NOW())";
        
        $this->query($sql, [
            ':user_id' => $userId,
            ':agreement_id' => $agreementId,
            ':agreement_type' => $type,
            ':version' => $version,
            ':ip' => Security::getClientIp(),
            ':ua' => Security::getUserAgent()
        ]);
    }

    /**
     * Log History
     */
    public function logHistory(int $agreementId, string $action, int $performedBy, ?string $details = null): void {
        $sql = "INSERT INTO `agreement_history` (`agreement_id`, `action`, `performed_by`, `details`, `created_at`) 
                VALUES (:aid, :act, :by, :details, NOW())";
        $this->query($sql, [
            ':aid' => $agreementId,
            ':act' => $action,
            ':by' => $performedBy,
            ':details' => $details
        ]);
    }

    /**
     * Get Agreement History
     */
    public function getHistory(int $agreementId): array {
        $sql = "SELECT ah.*, u.username as performer_username, u.first_name, u.last_name
                FROM `agreement_history` ah
                LEFT JOIN `users` u ON ah.performed_by = u.id
                WHERE ah.agreement_id = :aid
                ORDER BY ah.created_at DESC";
        return $this->fetchAll($sql, [':aid' => $agreementId]);
    }
}
