<?php

use classes\db;
use classes\department_daily_report_complaints_schema_bootstrap;
use objects\department_daily_report_complaints_o;

function department_daily_report_complaints_integration_db(): db
{
    if (!integration_enabled()) {
        test()->markTestSkipped('Set RUN_INTEGRATION_TESTS=1 to run DB integration tests.');
    }

    $host = getenv('CONFIG_DB_HOST') ?: null;
    $user = getenv('CONFIG_DB_USER') ?: null;
    $password = getenv('CONFIG_DB_PASSWORD') ?: '';
    $database = getenv('CONFIG_DB_DATABASE') ?: null;
    $port = getenv('CONFIG_DB_PORT');
    if (!$host || !$user || !$database) {
        test()->markTestSkipped('Missing DB env vars: CONFIG_DB_HOST/CONFIG_DB_USER/CONFIG_DB_DATABASE.');
    }

    app_require('classes/db.php');
    app_require('classes/department_daily_report_complaints_schema_bootstrap.php');
    app_require('objects/department_daily_report_complaints_o.php');

    if (!defined('objects\redis')) {
        define('objects\redis', new class {
            private array $department_names = [];
            private array $user_ids_by_customer_number = [];
            private array $customer_numbers_by_user_id = [];

            public function get_department_name(int $department_id): ?string
            {
                return $this->department_names[$department_id] ?? null;
            }

            public function cache_department_name(int $department_id, string $department_name): void
            {
                $this->department_names[$department_id] = $department_name;
            }

            public function cache_user_id_from_customer_number(int $customer_number, int $user_id): void
            {
                $this->user_ids_by_customer_number[$customer_number] = $user_id;
            }

            public function cache_customer_number_from_user_id(int $user_id, int $customer_number): void
            {
                $this->customer_numbers_by_user_id[$user_id] = $customer_number;
            }

            public function get_user_id_from_customer_number(int $customer_number): ?int
            {
                return $this->user_ids_by_customer_number[$customer_number] ?? null;
            }

            public function get_customer_number_from_user_id(int $user_id): ?int
            {
                return $this->customer_numbers_by_user_id[$user_id] ?? null;
            }
        });
    }

    $GLOBALS['response'] = new class {
        public function error(string $message): void
        {
            throw new RuntimeException($message);
        }

        public function internal_server_error(string $message): void
        {
            throw new RuntimeException($message);
        }
    };

    $db = new db([
        'host' => $host,
        'user' => $user,
        'password' => $password,
        'database' => $database,
        'port' => $port !== false && $port !== null ? (int)$port : 3306,
    ]);
    $db->connect();
    $GLOBALS['db'] = $db;
    department_daily_report_complaints_schema_bootstrap::ensureTables();

    return $db;
}

it('counts complaint rows by department and created_at reporting range', function (): void {
    $db = department_daily_report_complaints_integration_db();
    $repository = new department_daily_report_complaints_o();
    $suffix = (string)random_int(10000, 99999);
    $department_ids = [];
    $complaint_ids = [];

    try {
        $db->query("INSERT INTO departments (name, description) VALUES ('" . $db->escape_string('Complaints A ' . $suffix) . "', 'Integration A')");
        $department_a_id = (int)$db->insert_id();
        $department_ids[] = $department_a_id;

        $db->query("INSERT INTO departments (name, description) VALUES ('" . $db->escape_string('Complaints B ' . $suffix) . "', 'Integration B')");
        $department_b_id = (int)$db->insert_id();
        $department_ids[] = $department_b_id;

        $complaint_one = $repository->addComplaint($department_a_id, null, '2026-03-23', 'service', 'Complaint one', 1);
        $complaint_two = (new department_daily_report_complaints_o())->addComplaint($department_a_id, 12345, '2026-03-24', 'damage_mirrors', 'Complaint two', 2);
        $complaint_three = (new department_daily_report_complaints_o())->addComplaint($department_b_id, null, '2026-03-24', 'other', 'Complaint three', 3);
        $complaint_ids = [
            (int)$complaint_one->id,
            (int)$complaint_two->id,
            (int)$complaint_three->id,
        ];

        $db->query("UPDATE department_daily_report_complaints SET wash_date = NULL, category = NULL WHERE id = " . (int)$complaint_one->id);
        $db->query("UPDATE department_daily_report_complaints SET created_at = '2026-03-23 08:00:00' WHERE id = " . (int)$complaint_one->id);
        $db->query("UPDATE department_daily_report_complaints SET created_at = '2026-03-24 09:15:00' WHERE id = " . (int)$complaint_two->id);
        $db->query("UPDATE department_daily_report_complaints SET created_at = '2026-03-24 10:30:00' WHERE id = " . (int)$complaint_three->id);

        $single_department_day_count = $repository->countForDepartmentsInRange([$department_a_id], '2026-03-23', '2026-03-23');
        $combined_range_count = $repository->countForDepartmentsInRange([$department_a_id, $department_b_id], '2026-03-23', '2026-03-24');
        $second_day_count = $repository->countForDepartmentsInRange([$department_a_id, $department_b_id], '2026-03-24', '2026-03-24');

        expect($single_department_day_count)->toBe(1);
        expect($combined_range_count)->toBe(3);
        expect($second_day_count)->toBe(2);
        $complaint_two_data = $complaint_two->asArray();
        expect($complaint_two_data['department_id'])->toBe($department_a_id);
        expect($complaint_two_data['customer_number'])->toBe(12345);
        expect($complaint_two_data['wash_date'])->toBe('2026-03-24');
        expect($complaint_two_data['category'])->toBe('damage_mirrors');
        expect($complaint_two_data['description'])->toBe('Complaint two');
        expect($complaint_two_data['created_by'])->toBe(2);
    } finally {
        if ($complaint_ids !== []) {
            $db->query('DELETE FROM department_daily_report_complaints WHERE id IN (' . implode(',', array_map('intval', $complaint_ids)) . ')');
        }
        if ($department_ids !== []) {
            $db->query('DELETE FROM departments WHERE id IN (' . implode(',', array_map('intval', $department_ids)) . ')');
        }
        $db->close();
    }
});

it('updates and deletes complaint rows', function (): void {
    $db = department_daily_report_complaints_integration_db();
    $repository = new department_daily_report_complaints_o();
    $suffix = (string)random_int(10000, 99999);
    $department_ids = [];
    $complaint_id = null;

    try {
        $db->query("INSERT INTO departments (name, description) VALUES ('" . $db->escape_string('Complaints Update A ' . $suffix) . "', 'Integration update A')");
        $department_a_id = (int)$db->insert_id();
        $department_ids[] = $department_a_id;

        $db->query("INSERT INTO departments (name, description) VALUES ('" . $db->escape_string('Complaints Update B ' . $suffix) . "', 'Integration update B')");
        $department_b_id = (int)$db->insert_id();
        $department_ids[] = $department_b_id;

        $complaint = $repository->addComplaint($department_a_id, null, '2026-03-23', 'service', 'Original complaint', 11);
        $complaint_id = (int)$complaint->id;

        $complaint->update([
            'department_id' => $department_b_id,
            'customer_number' => 54321,
            'wash_date' => '2026-03-24',
            'category' => 'damage_paint',
            'description' => 'Updated complaint',
        ]);

        $updated = (new department_daily_report_complaints_o())->select($complaint_id);
        $updated_data = $updated->asArray();
        expect($updated_data['id'])->toBe($complaint_id);
        expect($updated_data['department_id'])->toBe($department_b_id);
        expect($updated_data['customer_number'])->toBe(54321);
        expect($updated_data['wash_date'])->toBe('2026-03-24');
        expect($updated_data['category'])->toBe('damage_paint');
        expect($updated_data['description'])->toBe('Updated complaint');
        expect($updated_data['created_by'])->toBe(11);

        $updated->deletePermanently();
        expect((new department_daily_report_complaints_o())->select($complaint_id)->exists())->toBeFalse();
    } finally {
        if ($complaint_id !== null) {
            $db->query('DELETE FROM department_daily_report_complaints WHERE id = ' . (int)$complaint_id);
        }
        if ($department_ids !== []) {
            $db->query('DELETE FROM departments WHERE id IN (' . implode(',', array_map('intval', $department_ids)) . ')');
        }
        $db->close();
    }
});

it('parses created_by_name from the users table', function (): void {
    $db = department_daily_report_complaints_integration_db();
    $repository = new department_daily_report_complaints_o();
    $suffix = (string)random_int(10000, 99999);
    $department_ids = [];
    $complaint_id = null;
    $user_id = null;
    $customer_number = (string)random_int(70000000, 79999999);

    try {
        $db->query("INSERT INTO departments (name, description) VALUES ('" . $db->escape_string('Complaints Parse ' . $suffix) . "', 'Integration parse')");
        $department_id = (int)$db->insert_id();
        $department_ids[] = $department_id;

        $escaped_customer_number = $db->escape_string($customer_number);
        $escaped_display_name = $db->escape_string('Complaint Parser User ' . $suffix);
        $escaped_password = $db->escape_string(password_hash('integration-password', PASSWORD_DEFAULT));
        $db->query(
            "INSERT INTO users (customer_number, password, group_id, display_name)
             VALUES ('$escaped_customer_number', '$escaped_password', 1, '$escaped_display_name')"
        );
        $user_id = (int)$db->insert_id();

        $complaint = $repository->addComplaint($department_id, null, '2026-03-23', 'wash_quality', 'Complaint with parsed staff name', $user_id);
        $complaint_id = (int)$complaint->id;

        $parsed = $repository->parseComplaint($complaint->asArray());

        expect($parsed['created_by'])->toBe($user_id);
        expect($parsed['created_by_name'])->toBe('Complaint Parser User ' . $suffix);
        expect($parsed['department_name'])->toBe('Complaints Parse ' . $suffix);
        expect($parsed['wash_date'])->toBe('2026-03-23');
        expect($parsed['category'])->toBe('wash_quality');
    } finally {
        if ($complaint_id !== null) {
            $db->query('DELETE FROM department_daily_report_complaints WHERE id = ' . (int)$complaint_id);
        }
        if ($user_id !== null) {
            $db->query('DELETE FROM users WHERE id = ' . (int)$user_id);
        }
        if ($department_ids !== []) {
            $db->query('DELETE FROM departments WHERE id IN (' . implode(',', array_map('intval', $department_ids)) . ')');
        }
        $db->close();
    }
});
