<?php

declare(strict_types=1);

namespace Tests;

use App\Models\Database;
use PHPUnit\Framework\TestCase as PHPUnitTestCase;

abstract class TestCase extends PHPUnitTestCase
{
    protected static bool $migrated = false;

    protected function setUp(): void
    {
        parent::setUp();

        if (!static::$migrated) {
            $this->setupTestDatabase();
            static::$migrated = true;
        }

        $this->truncateTables();
    }

    protected function tearDown(): void
    {
        Database::reset();
        parent::tearDown();
    }

    private function setupTestDatabase(): void
    {
        $host = $_ENV['DB_HOST'] ?? '127.0.0.1';
        $port = $_ENV['DB_PORT'] ?? '3306';
        $user = $_ENV['DB_USER'] ?? 'root';
        $pass = $_ENV['DB_PASS'] ?? '';
        $dbName = $_ENV['DB_NAME'] ?? 'italvet_test';

        try {
            $dsn = "mysql:host={$host};port={$port};charset=utf8mb4";
            $pdo = new \PDO($dsn, $user, $pass, [
                \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
            ]);

            $pdo->exec("DROP DATABASE IF EXISTS `{$dbName}`");
            $pdo->exec("CREATE DATABASE `{$dbName}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
            $pdo->exec("USE `{$dbName}`");

            $migrations = glob(BASE_PATH . '/database/migrations/*.sql');
            sort($migrations);
            foreach ($migrations as $migrationFile) {
                if (file_exists($migrationFile)) {
                    $sql = file_get_contents($migrationFile);
                    $pdo->exec($sql);
                }
            }
        } catch (\PDOException $e) {
            throw new \RuntimeException('Error setting up test database: ' . $e->getMessage());
        }
    }

    private function truncateTables(): void
    {
        $db = Database::connect();
        $db->exec('SET FOREIGN_KEY_CHECKS = 0');
        $db->exec('TRUNCATE TABLE password_resets');
        $db->exec('TRUNCATE TABLE user_invitations');
        $db->exec('TRUNCATE TABLE sessions');
        $db->exec('TRUNCATE TABLE tasks');
        $db->exec('TRUNCATE TABLE notes');
        $db->exec('TRUNCATE TABLE lead_status_history');
        $db->exec('TRUNCATE TABLE lead_products');
        $db->exec('TRUNCATE TABLE lead_technical_profiles');
        $db->exec('TRUNCATE TABLE leads');
        $db->exec('TRUNCATE TABLE event_users');
        $db->exec('TRUNCATE TABLE events');
        $db->exec('TRUNCATE TABLE products');
        $db->exec('TRUNCATE TABLE technical_materials');
        $db->exec('TRUNCATE TABLE whatsapp_templates');
        $db->exec('TRUNCATE TABLE audit_logs');
        $db->exec('TRUNCATE TABLE notifications');
        $db->exec('TRUNCATE TABLE backups');
        $db->exec('TRUNCATE TABLE configurations');
        $db->exec('TRUNCATE TABLE users');
        $db->exec('SET FOREIGN_KEY_CHECKS = 1');
    }

    protected function createTestUser(string $email = 'test@italvet.com', string $role = 'comercial_manager', string $status = 'active'): int
    {
        $db = Database::connect();
        $hash = password_hash('Password123!', PASSWORD_BCRYPT);
        $stmt = $db->prepare(
            'INSERT INTO users (name, email, password, role, status) VALUES (:name, :email, :password, :role, :status)'
        );
        $stmt->execute([
            'name' => 'Test User',
            'email' => $email,
            'password' => $hash,
            'role' => $role,
            'status' => $status,
        ]);
        return (int) $db->lastInsertId();
    }

    protected function createTestSession(int $userId, string $token): void
    {
        $db = Database::connect();
        $stmt = $db->prepare(
            "INSERT INTO sessions (user_id, token, ip_address, user_agent, expires_at)
             VALUES (:user_id, :token, '127.0.0.1', 'PHPUnit', DATE_ADD(NOW(), INTERVAL 3600 SECOND))"
        );
        $stmt->execute([
            'user_id' => $userId,
            'token' => $token,
        ]);
    }

    protected function createTestPasswordReset(int $userId, string $token): void
    {
        $db = Database::connect();
        $stmt = $db->prepare(
            "INSERT INTO password_resets (user_id, token, expires_at, used)
             VALUES (:user_id, :token, DATE_ADD(NOW(), INTERVAL 3600 SECOND), 0)"
        );
        $stmt->execute([
            'user_id' => $userId,
            'token' => $token,
        ]);
    }

    protected function createTestEvent(string $name = 'Test Event', int $userId = 0): int
    {
        $db = Database::connect();
        $stmt = $db->prepare(
            "INSERT INTO events (name, description, location, status) VALUES (:name, 'Test', 'Test', 'active')"
        );
        $stmt->execute(['name' => $name]);
        $eventId = (int) $db->lastInsertId();

        if ($userId > 0) {
            $db->prepare("INSERT INTO event_users (event_id, user_id) VALUES (:eid, :uid)")
               ->execute(['eid' => $eventId, 'uid' => $userId]);
        }

        return $eventId;
    }
}
