'use strict';

const fs = require('fs');
const path = require('path');

const root = __dirname;
const read = (name) => fs.readFileSync(path.join(root, name), 'utf8');
const checks = [];
const check = (name, condition) => checks.push({ name, passed: Boolean(condition) });

const schema = read('database.sql');
const migration = read('upgrade_v3_16.sql');
const functions = read('app/functions.php');
const users = read('users.php');
const create = read('ticket_create.php');
const view = read('ticket_view.php');
const attachments = read('attachment_download.php');

check('five role codes in schema', ['USERF', 'OFCF', 'VHCF', 'ICTF', 'OTHF'].every((code) => schema.includes(`'${code}'`)));
check('unique user-role constraint', schema.includes('UNIQUE KEY uq_user_roles_user_role (user_id, role_id)'));
check('system admin separated', schema.includes('is_system_admin') && !/role ENUM\\('admin', 'agent', 'user'\\)/.test(schema));
check('category responsible role', schema.includes('ticket_categories') && schema.includes('responsible_role_code'));
check('ticket responsible role', schema.includes('idx_tickets_responsible_role_status'));
check('migration drops legacy role', migration.includes('DROP COLUMN role'));
check('migration preserves assigned_to', !migration.includes('DROP COLUMN assigned_to'));
check('ticket access uses role EXISTS', functions.includes('r_access.role_code = t.responsible_role_code'));
check('multi-role list avoids joins/duplicates', functions.includes('EXISTS (') && functions.includes('ur_access.user_id = ?'));
check('role notifications distinct', functions.includes('SELECT DISTINCT u.id'));
check('server-side admin guard', functions.includes('function require_system_admin'));
check('server-side ticket guard', functions.includes('function can_manage_ticket'));
check('role input allowlist', functions.includes('function normalize_role_codes'));
check('user role audit', functions.includes('INSERT INTO user_role_events'));
check('automatic routing on create', create.includes('category_responsible_role_code($category)'));
check('category transfer audit', view.includes("'category_changed'") && view.includes("'responsible_role_changed'"));
check('assignment validates responsible role', view.includes('r.role_code = ?'));
check('claim validates business role', view.includes("if ($action === 'claim'"));
check('attachment BOLA uses ticket guard', attachments.includes('can_view_ticket($attachment, $user)'));
check('multi-select roles in admin UI', users.includes('name="roles[]"'));
check('last system admin protected', users.includes('Poslednji aktivni sistemski administrator'));

const canView = (user, ticket) =>
    user.active && (
        user.systemAdmin ||
        user.id === ticket.ownerId ||
        ticket.participants.includes(user.id) ||
        user.roles.includes(ticket.role)
    );
const canManage = (user, ticket) =>
    user.active && (user.systemAdmin || user.roles.includes(ticket.role));
const queue = (user, tickets) => tickets.filter((ticket) => canView(user, ticket)).map((ticket) => ticket.id);

const sampleTickets = [
    { id: 1, ownerId: 10, participants: [], role: 'OFCF' },
    { id: 2, ownerId: 11, participants: [], role: 'VHCF' },
    { id: 3, ownerId: 12, participants: [], role: 'ICTF' },
    { id: 4, ownerId: 13, participants: [], role: 'OTHF' },
];
check('USERF cannot view another user ticket', !canView({ id: 99, active: true, systemAdmin: false, roles: ['USERF'] }, sampleTickets[0]));
check('OFCF sees only OFCF queue', JSON.stringify(queue({ id: 99, active: true, systemAdmin: false, roles: ['OFCF'] }, sampleTickets)) === '[1]');
check('VHCF sees only VHCF queue', JSON.stringify(queue({ id: 99, active: true, systemAdmin: false, roles: ['VHCF'] }, sampleTickets)) === '[2]');
check('ICTF sees only ICTF queue', JSON.stringify(queue({ id: 99, active: true, systemAdmin: false, roles: ['ICTF'] }, sampleTickets)) === '[3]');
check('OTHF sees only OTHF queue', JSON.stringify(queue({ id: 99, active: true, systemAdmin: false, roles: ['OTHF'] }, sampleTickets)) === '[4]');
check('multi-role user sees union once', JSON.stringify(queue({ id: 99, active: true, systemAdmin: false, roles: ['OFCF', 'ICTF', 'OFCF'] }, sampleTickets)) === '[1,3]');
check('no-role user cannot manage', !canManage({ id: 99, active: true, systemAdmin: false, roles: [] }, sampleTickets[0]));
check('deactivated role user has no access', !canView({ id: 99, active: false, systemAdmin: false, roles: ['OFCF'] }, sampleTickets[0]));
check('participant retains public ticket access', canView({ id: 77, active: true, systemAdmin: false, roles: [] }, { ...sampleTickets[0], participants: [77] }));
check('system admin sees all queues', queue({ id: 99, active: true, systemAdmin: true, roles: [] }, sampleTickets).length === 4);

const failed = checks.filter((item) => !item.passed);
for (const item of checks) {
    process.stdout.write(`${item.passed ? 'PASS' : 'FAIL'}  ${item.name}\n`);
}
process.stdout.write(`\n${checks.length - failed.length}/${checks.length} checks passed.\n`);
process.exitCode = failed.length ? 1 : 0;
