<?php

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

class CustomerAddress
{
    private PDO $db;

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

    public function getByUserId(int $userId): array
    {
        $sql = "
            SELECT *
            FROM customer_addresses
            WHERE user_id = :user_id
            ORDER BY is_default DESC, id DESC
        ";

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

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

        return $stmt->fetchAll();
    }

    public function findOwned(
        int $addressId,
        int $userId
    ): ?array {

        $sql = "
            SELECT *
            FROM customer_addresses
            WHERE id = :id
              AND user_id = :user_id
            LIMIT 1
        ";

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

        $stmt->execute([
            'id' => $addressId,
            'user_id' => $userId
        ]);

        $address = $stmt->fetch();

        return $address ?: null;
    }

    public function create(
        int $userId,
        array $data
    ): int {

        $this->db->beginTransaction();

        try {

            $isDefault = !empty($data['is_default']);

            if (!$isDefault) {

                $stmt = $this->db->prepare("
                    SELECT id
                    FROM customer_addresses
                    WHERE user_id = :user_id
                      AND is_default = 1
                    LIMIT 1
                    FOR UPDATE
                ");

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

                $isDefault = $stmt->fetchColumn() === false;
            }

            if ($isDefault) {

                $stmt = $this->db->prepare("
                    UPDATE customer_addresses
                    SET is_default = 0
                    WHERE user_id = :user_id
                ");

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

            $sql = "
                INSERT INTO customer_addresses (
                    user_id,
                    recipient_name,
                    phone,
                    address_line,
                    ward,
                    district,
                    province,
                    is_default
                )
                VALUES (
                    :user_id,
                    :recipient_name,
                    :phone,
                    :address_line,
                    :ward,
                    :district,
                    :province,
                    :is_default
                )
            ";

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

            $stmt->execute([
                'user_id' => $userId,
                'recipient_name' => $data['recipient_name'],
                'phone' => $data['phone'],
                'address_line' => $data['address_line'],
                'ward' => $data['ward'] ?: null,
                'district' => $data['district'] ?: null,
                'province' => $data['province'] ?: null,
                'is_default' => $isDefault ? 1 : 0
            ]);

            $id = (int) $this->db->lastInsertId();

            $this->db->commit();

            return $id;

        } catch (Throwable $e) {

            $this->db->rollBack();

            throw $e;
        }
    }
    public function update(
    int $addressId,
    int $userId,
    array $data
): void {

    $this->db->beginTransaction();

    try {

        if (!empty($data['is_default'])) {

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

                    SET is_default = 0

                    WHERE user_id = :user_id
                ");

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


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

                SET
                    recipient_name = :recipient_name,
                    phone = :phone,
                    address_line = :address_line,
                    ward = :ward,
                    district = :district,
                    province = :province,
                    is_default = :is_default

                WHERE id = :id
                  AND user_id = :user_id
            ");


        $stmt->execute([
            'recipient_name' =>
                $data['recipient_name'],

            'phone' =>
                $data['phone'],

            'address_line' =>
                $data['address_line'],

            'ward' =>
                $data['ward'] ?: null,

            'district' =>
                $data['district'] ?: null,

            'province' =>
                $data['province'] ?: null,

            'is_default' =>
                !empty($data['is_default'])
                    ? 1
                    : 0,

            'id' =>
                $addressId,

            'user_id' =>
                $userId
        ]);


        $this->db->commit();

    } catch (Throwable $e) {

        $this->db->rollBack();

        throw $e;
    }
}


public function delete(
    int $addressId,
    int $userId
): void {

    $this->db->beginTransaction();

    try {

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

                FROM customer_addresses

                WHERE id = :id
                  AND user_id = :user_id

                LIMIT 1

                FOR UPDATE
            ");

        $stmt->execute([
            'id' => $addressId,
            'user_id' => $userId
        ]);

        $address = $stmt->fetch();

        if (!$address) {
            $this->db->commit();

            return;
        }

        $stmt =
            $this->db->prepare("
                DELETE FROM customer_addresses

                WHERE id = :id
                  AND user_id = :user_id
            ");

        $stmt->execute([
            'id' => $addressId,
            'user_id' => $userId
        ]);

        if ((int) $address['is_default'] === 1) {

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

                    FROM customer_addresses

                    WHERE user_id = :user_id

                    ORDER BY id DESC

                    LIMIT 1

                    FOR UPDATE
                ");

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

            $replacementId = $stmt->fetchColumn();

            if ($replacementId !== false) {

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

                        SET is_default = 1

                        WHERE id = :id
                          AND user_id = :user_id
                    ");

                $stmt->execute([
                    'id' => (int) $replacementId,
                    'user_id' => $userId
                ]);
            }
        }

        $this->db->commit();

    } catch (Throwable $e) {

        if ($this->db->inTransaction()) {
            $this->db->rollBack();
        }

        throw $e;
    }
}


public function setDefault(
    int $addressId,
    int $userId
): void {

    $this->db->beginTransaction();

    try {

        $address =
            $this->findOwned(
                $addressId,
                $userId
            );

        if (!$address) {

            throw new RuntimeException(
                'Địa chỉ không tồn tại.'
            );
        }


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

                SET is_default = 0

                WHERE user_id = :user_id
            ");

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


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

                SET is_default = 1

                WHERE id = :id
                  AND user_id = :user_id
            ");

        $stmt->execute([
            'id' =>
                $addressId,

            'user_id' =>
                $userId
        ]);


        $this->db->commit();

    } catch (Throwable $e) {

        $this->db->rollBack();

        throw $e;
    }
}
}
