<?php

declare(strict_types=1);

namespace App\Repositories;

use App\Database;
use PDO;

final class InquiryRepository
{
    private PDO $db;

    public function __construct()
    {
        $this->db = Database::connection();
    }

    public function create(array $data): string
    {
        do {
            $ticket = 'GTS-' . date('Ymd') . '-' . strtoupper(bin2hex(random_bytes(3)));
            $check = $this->db->prepare('SELECT COUNT(*) FROM inquiries WHERE ticket = :ticket');
            $check->execute(['ticket' => $ticket]);
        } while ((int) $check->fetchColumn() > 0);

        $statement = $this->db->prepare(
            "INSERT INTO inquiries
             (ticket, name, phone, email, inquiry_type, title, body, password_hash, status, consent_at)
             VALUES (:ticket, :name, :phone, :email, :inquiry_type, :title, :body, :password_hash, 'pending', NOW())"
        );
        $statement->execute([
            'ticket' => $ticket,
            'name' => $data['name'],
            'phone' => $data['phone'],
            'email' => $data['email'] ?: null,
            'inquiry_type' => $data['type'],
            'title' => $data['title'],
            'body' => $data['body'],
            'password_hash' => password_hash($data['password'], PASSWORD_DEFAULT),
        ]);

        return $ticket;
    }

    public function findForLookup(string $ticket): ?array
    {
        $statement = $this->db->prepare(
            'SELECT id, ticket, inquiry_type, title, body, status, reply, replied_at, created_at,
                    password_hash, lookup_failed_attempts, lookup_locked_until
             FROM inquiries WHERE ticket = :ticket AND deleted_at IS NULL LIMIT 1'
        );
        $statement->execute(['ticket' => strtoupper($ticket)]);
        $inquiry = $statement->fetch();
        return $inquiry ?: null;
    }

    public function resetLookupLimit(int $id): void
    {
        $statement = $this->db->prepare(
            'UPDATE inquiries
             SET lookup_failed_attempts = 0, lookup_locked_until = NULL
             WHERE id = :id AND deleted_at IS NULL'
        );
        $statement->execute(['id' => $id]);
    }

    public function recordLookupFailure(int $id): bool
    {
        $this->db->beginTransaction();
        try {
            $select = $this->db->prepare(
                'SELECT lookup_failed_attempts, lookup_locked_until
                 FROM inquiries WHERE id = :id AND deleted_at IS NULL FOR UPDATE'
            );
            $select->execute(['id' => $id]);
            $limit = $select->fetch();
            if (!$limit) {
                $this->db->rollBack();
                return false;
            }

            $attempts = (int) $limit['lookup_failed_attempts'];
            $lockedUntil = $limit['lookup_locked_until'];
            if (is_string($lockedUntil) && strtotime($lockedUntil) <= time()) {
                $attempts = 0;
            }
            $attempts++;
            $locked = $attempts >= 5;

            $update = $this->db->prepare(
                'UPDATE inquiries
                 SET lookup_failed_attempts = :attempts,
                     lookup_locked_until = CASE WHEN :locked = 1 THEN DATE_ADD(NOW(), INTERVAL 15 MINUTE) ELSE NULL END
                 WHERE id = :id'
            );
            $update->execute([
                'attempts' => $attempts,
                'locked' => $locked ? 1 : 0,
                'id' => $id,
            ]);
            $this->db->commit();
            return $locked;
        } catch (\Throwable $error) {
            if ($this->db->inTransaction()) {
                $this->db->rollBack();
            }
            throw $error;
        }
    }
}
