<?php

require_once BASE_PATH . '/config/database.php';

class Promotion
{
    private PDO $db;

    public function __construct()
    {
        $database = new Database();
        $this->db = $database->connect();
    }

    public function findValidByCode(
        string $code
    ): ?array {

        $sql = "
            SELECT *
            FROM promotions

            WHERE code = :code
              AND is_active = 1
              AND start_at <= NOW()
              AND end_at >= NOW()

              AND (
                    usage_limit IS NULL
                    OR used_count < usage_limit
              )

            LIMIT 1
        ";

        $stmt = $this->db->prepare($sql);

        $stmt->execute([
            'code' => strtoupper(trim($code))
        ]);

        $promotion = $stmt->fetch();

        return $promotion ?: null;
    }

    public function calculateDiscount(
        array $promotion,
        float $subtotal
    ): float {

        if (
            $subtotal
            < (float) $promotion['min_order_value']
        ) {
            return 0;
        }

        if ($promotion['discount_type'] === 'percent') {

            $discount =
                $subtotal
                * ((float) $promotion['discount_value'] / 100);

        } else {

            $discount =
                (float) $promotion['discount_value'];
        }

        if (
            $promotion['max_discount'] !== null
            && $discount > (float) $promotion['max_discount']
        ) {

            $discount =
                (float) $promotion['max_discount'];
        }

        return min(
            $discount,
            $subtotal
        );
    }
    public function countForOwner(
    string $search = ''
): int {

    $params = [];

    $where = '1 = 1';


    if ($search !== '') {

        $where .= "
            AND code LIKE :search
        ";

        $params['search'] =
            '%' . $search . '%';
    }


    $stmt =
        $this->db->prepare("
            SELECT COUNT(*)

            FROM promotions

            WHERE {$where}
        ");


    $stmt->execute($params);


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


public function getForOwner(
    string $search = '',
    int $limit = 15,
    int $offset = 0
): array {

    $params = [];

    $where = '1 = 1';


    if ($search !== '') {

        $where .= "
            AND code LIKE :search
        ";

        $params['search'] =
            '%' . $search . '%';
    }


    $limit = max(
        1,
        $limit
    );

    $offset = max(
        0,
        $offset
    );


    $stmt =
        $this->db->prepare("
            SELECT *

            FROM promotions

            WHERE {$where}

            ORDER BY created_at DESC

            LIMIT {$limit}
            OFFSET {$offset}
        ");


    $stmt->execute($params);


    return $stmt->fetchAll();
}


public function findById(
    int $id
): ?array {

    $stmt =
        $this->db->prepare("
            SELECT *

            FROM promotions

            WHERE id = :id

            LIMIT 1
        ");


    $stmt->execute([
        'id' => $id
    ]);


    $promotion =
        $stmt->fetch();


    return $promotion ?: null;
}


public function codeExists(
    string $code,
    ?int $excludeId = null
): bool {

    $sql = "
        SELECT COUNT(*)

        FROM promotions

        WHERE code = :code
    ";

    $params = [
        'code' =>
            strtoupper(
                trim($code)
            )
    ];


    if ($excludeId !== null) {

        $sql .= "
            AND id != :exclude_id
        ";

        $params['exclude_id'] =
            $excludeId;
    }


    $stmt =
        $this->db->prepare($sql);

    $stmt->execute($params);


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

public function create(array $data): int
{
    $stmt = $this->db->prepare("
        INSERT INTO promotions (
            name,
            code,
            description,
            discount_type,
            discount_value,
            min_order_value,
            max_discount,
            start_at,
            end_at,
            usage_limit,
            used_count,
            is_active
        )
        VALUES (
            :name,
            :code,
            :description,
            :discount_type,
            :discount_value,
            :min_order_value,
            :max_discount,
            :start_at,
            :end_at,
            :usage_limit,
            0,
            :is_active
        )
    ");

    $stmt->execute([
        'name' => $data['name'],
        'code' => $data['code'],
        'description' => $data['description'] ?: null,
        'discount_type' => $data['discount_type'],
        'discount_value' => $data['discount_value'],
        'min_order_value' => $data['min_order_value'],
        'max_discount' => $data['max_discount'],
        'start_at' => $data['start_at'],
        'end_at' => $data['end_at'],
        'usage_limit' => $data['usage_limit'],
        'is_active' => $data['is_active']
    ]);

    return (int) $this->db->lastInsertId();
}

public function updatePromotion(
    int $id,
    array $data
): void {

    $stmt = $this->db->prepare("
        UPDATE promotions
        SET
            name = :name,
            code = :code,
            description = :description,
            discount_type = :discount_type,
            discount_value = :discount_value,
            min_order_value = :min_order_value,
            max_discount = :max_discount,
            start_at = :start_at,
            end_at = :end_at,
            usage_limit = :usage_limit,
            is_active = :is_active
        WHERE id = :id
    ");

    $stmt->execute([
        'name' => $data['name'],
        'code' => $data['code'],
        'description' => $data['description'] ?: null,
        'discount_type' => $data['discount_type'],
        'discount_value' => $data['discount_value'],
        'min_order_value' => $data['min_order_value'],
        'max_discount' => $data['max_discount'],
        'start_at' => $data['start_at'],
        'end_at' => $data['end_at'],
        'usage_limit' => $data['usage_limit'],
        'is_active' => $data['is_active'],
        'id' => $id
    ]);
}


public function toggleActive(
    int $id
): void {

    $stmt =
        $this->db->prepare("
            UPDATE promotions

            SET is_active =
                CASE
                    WHEN is_active = 1
                    THEN 0
                    ELSE 1
                END

            WHERE id = :id
        ");


    $stmt->execute([
        'id' => $id
    ]);
}
}