'use strict';

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

const root = __dirname;
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8');
const files = {
  functions: read('app/functions.php'),
  header: read('app/header.php'),
  tickets: read('tickets.php'),
  ticketView: read('ticket_view.php'),
  dashboard: read('dashboard.php'),
  css: read('assets/css/style.css'),
  logo: read('assets/img/sos-decija-sela-srbija.svg'),
  sql: read('sosmthhg_infratest.sql'),
};

const results = [];
function check(name, condition, detail = '') {
  results.push({ name, ok: Boolean(condition), detail });
}

check('Dinamičko učitavanje aktivnih uloga iz baze', /SELECT role_code, name FROM roles WHERE is_active = 1/.test(files.functions));
check('Osnovne uloge su centralizovane kao USERF i USERDS', /function base_user_role_codes\(\): array[\s\S]*return \['USERF', 'USERDS'\];/.test(files.functions));
check('Dodatna uloga nije hardkodovana na konkretnog korisnika', /function user_additional_role_codes/.test(files.functions) && !/username\s*===|email\s*===/.test(files.functions));
check('Moji tiketi uključuju podnosioca, direktnu dodelu i učesnika', /function my_tickets_access_sql[\s\S]*t\.user_id = \?[\s\S]*t\.assigned_to = \?[\s\S]*tp_mine\.user_id = \?/.test(files.functions));
check('Zaduženi tiketi uključuju direktnu dodelu', /function assigned_tickets_access_sql[\s\S]*t\.assigned_to = \?/.test(files.functions));
check('Zaduženi tiketi uključuju aktivnu dodatnu ulogu', /ur_assigned[\s\S]*r_assigned\.is_active = 1[\s\S]*r_assigned\.role_code = t\.responsible_role_code/.test(files.functions));
check('Obe osnovne uloge su isključene iz rutiranja', /r_assigned\.role_code NOT IN \([\s\S]*basePlaceholders/.test(files.functions) || /r_assigned\.role_code NOT IN \('/.test(files.functions));
check('Nedozvoljeni assigned prikaz vraća HTTP 403', /requestedView === 'assigned'[\s\S]*http_response_code\(403\)/.test(files.functions));
check('Nevalidan prikaz vraća HTTP 403', /Nemate pravo pristupa traženom prikazu tiketa/.test(files.functions));
check('Neskalarni view parametar je odbijen pre obrade', /!is_scalar\(\$requestedView\)/.test(files.functions));
check('Lista koristi odvojeni view resolver', /ticket_list_view\(\$user, \$_GET\['view'\]/.test(files.tickets));
check('Lista koristi view-specifičan SQL pristup', /ticket_list_access_sql\(\$user, \$view\)/.test(files.tickets));
check('Filter zadržava izabrani prikaz', /name="view" value="<\?= e\(\$view\)/.test(files.tickets));
check('Navigacija uvek prikazuje Moje tikete', /tickets\.php\?view=mine[\s\S]*Moji tiketi/.test(files.header));
check('Navigacija uslovno prikazuje zadužene tikete', /if \(user_has_additional_role\(\$user\)\)[\s\S]*tickets\.php\?view=assigned/.test(files.header));
check('Administrator ima poseban prikaz svih tiketa', /tickets\.php\?view=all[\s\S]*Svi zahtevi/.test(files.header));
check('Aktivna navigaciona stavka koristi postojeću klasu aktivan', /activeTicketView === 'mine' \? 'aktivan' : ''/.test(files.header));
check('Detalj tiketa dozvoljava direktno zaduženog korisnika', /can_view_ticket[\s\S]*assigned_to/.test(files.functions));
check('Upravljanje tiketom dozvoljava direktno zaduženog korisnika', /can_manage_ticket[\s\S]*assigned_to/.test(files.functions));
check('Logo je postavljen na login stranici', /hero-brend[\s\S]*src=\"<\?= e\(\$brandLogoUrl\)/.test(files.header));
check('Logo je postavljen u zaglavlju nakon prijave', /sidebar-brend[\s\S]*src=\"<\?= e\(\$brandLogoUrl\)/.test(files.header));
check('Logo koristi proporcionalno skaliranje', /\.brand-logo[\s\S]*object-fit:\s*contain/.test(files.css));
check('Logo asset je validan SVG dokument', /^<\?xml[\s\S]*<svg[\s\S]*SOS Dečija sela Srbija/.test(files.logo));
check('CSS i JavaScript cache verzija je 3.25.0', files.header.includes('?v=3.25.0') && (files.header.match(/\?v=3\.25\.0/g) || []).length >= 2);
check('Logo koristi automatski cache-busting', /filemtime\(\$brandLogoAbsolutePath\)/.test(files.header) && /\?v=' \. rawurlencode\(\$brandLogoVersion\)/.test(files.header));
check('Logo nema dodatni unutrašnji razmak', /\.brand-mark \{[\s\S]*padding:\s*0/.test(files.css));
check('Mobilni prikaz switch-a je definisan', /@media \(max-width: 640px\)[\s\S]*\.ticket-view-switch/.test(files.css));
check('Obrada tiketa grupiše update i claim forme u poseban spacing wrapper', /ticket-processing-forms[\s\S]*Sačuvaj izmene[\s\S]*Preuzmi tiket/.test(files.ticketView));
check('Spacing wrapper koristi postojeći grid gap od 15px', /\.ticket-processing-forms \{\s*display: grid;\s*gap: 15px;\s*\}/.test(files.css));
check('CSS vitičaste zagrade su izbalansirane', (files.css.match(/\{/g) || []).length === (files.css.match(/\}/g) || []).length);
check('SQL šema sadrži relaciju više uloga po korisniku', /CREATE TABLE `user_roles`[\s\S]*`user_id`[\s\S]*`role_id`/.test(files.sql));
check('SQL šema tiketa sadrži vlasnika, direktno zaduženje i odgovornu ulogu', /CREATE TABLE `tickets`[\s\S]*`user_id`[\s\S]*`assigned_to`[\s\S]*`responsible_role_code`/.test(files.sql));

// Nezavisna simulacija poslovnih scenarija prema implementiranim pravilima.
const BASES = new Set(['USERF', 'USERDS']);
const hasAdditionalRole = (roles) => roles.some((role) => !BASES.has(role));
const mine = (user, tickets) => tickets.filter((ticket) => ticket.user_id === user.id || ticket.assigned_to === user.id || ticket.participants.includes(user.id));
const assigned = (user, tickets) => {
  if (!hasAdditionalRole(user.roles)) return [];
  const additional = new Set(user.roles.filter((role) => !BASES.has(role)));
  return tickets.filter((ticket) => ticket.assigned_to === user.id || additional.has(ticket.responsible_role_code));
};

const sampleTickets = [
  { id: 1, user_id: 10, assigned_to: null, responsible_role_code: 'ICTF', participants: [] },
  { id: 2, user_id: 20, assigned_to: 10, responsible_role_code: 'VHCF', participants: [] },
  { id: 3, user_id: 10, assigned_to: 10, responsible_role_code: 'ICTF', participants: [10] },
  { id: 4, user_id: 30, assigned_to: null, responsible_role_code: 'OFCF', participants: [10] },
  { id: 5, user_id: 40, assigned_to: null, responsible_role_code: 'VHCF', participants: [] },
];

const baseUser = { id: 10, roles: ['USERF'] };
const baseDsUser = { id: 50, roles: ['USERDS'] };
const vehicleCoordinator = { id: 10, roles: ['USERF', 'VHCF'] };
const multiRoleUser = { id: 10, roles: ['USERF', 'VHCF', 'ICTF'] };
const dsIctCoordinator = { id: 50, roles: ['USERDS', 'ICTDS'] };

check('Scenario: USERF vidi svoje, direktno dodeljene i participant tikete', JSON.stringify(mine(baseUser, sampleTickets).map((t) => t.id)) === JSON.stringify([1, 2, 3, 4]) && assigned(baseUser, sampleTickets).length === 0);
check('Scenario: USERF + jedna dodatna uloga dobija zadužene tikete', JSON.stringify(assigned(vehicleCoordinator, sampleTickets).map((t) => t.id)) === JSON.stringify([2, 3, 5]));
check('Scenario: više dodatnih uloga formira uniju zaduženja', JSON.stringify(assigned(multiRoleUser, sampleTickets).map((t) => t.id)) === JSON.stringify([1, 2, 3, 5]));
check('Scenario: isti tiket se u Moji tiketi pojavljuje samo jednom i može legitimno biti i u zaduženom prikazu', mine(multiRoleUser, sampleTickets).filter((t) => t.id === 3).length === 1 && assigned(multiRoleUser, sampleTickets).some((t) => t.id === 3));
check('Scenario: uklanjanje dodatnih uloga uklanja zaduženi prikaz', hasAdditionalRole(vehicleCoordinator.roles) && !hasAdditionalRole(baseUser.roles));
check('Scenario: direktna dodela ulazi u zadužene tikete', assigned(vehicleCoordinator, sampleTickets).some((t) => t.id === 2));
check('Scenario: učesnik bez vlasništva/dodele ulazi u Moji tiketi', mine(vehicleCoordinator, [{ id: 6, user_id: 99, assigned_to: null, responsible_role_code: 'OFCF', participants: [10] }]).length === 1);
check('Scenario: korisnik bez veze sa tiketom ne ulazi u Moji tiketi', mine(vehicleCoordinator, [{ id: 7, user_id: 99, assigned_to: 98, responsible_role_code: 'OFCF', participants: [77] }]).length === 0);
check('Scenario: USERDS bez dodatne uloge nema assigned queue', assigned(baseDsUser, sampleTickets).length === 0);
check('Scenario: ICTDS ne dobija ICTF tiket samo zbog iste funkcije', assigned(dsIctCoordinator, [{ id: 8, user_id: 99, assigned_to: null, responsible_role_code: 'ICTF', participants: [] }]).length === 0);
check('Scenario: ICTDS dobija tiket sa tačnim ICTDS kodom', assigned(dsIctCoordinator, [{ id: 9, user_id: 99, assigned_to: null, responsible_role_code: 'ICTDS', participants: [] }]).length === 1);


const failed = results.filter((result) => !result.ok);
for (const result of results) {
  console.log(`${result.ok ? 'PASS' : 'FAIL'} | ${result.name}${result.detail ? ` | ${result.detail}` : ''}`);
}
console.log(`\nRezultat: ${results.length - failed.length}/${results.length} provera uspešno.`);
if (failed.length > 0) process.exit(1);
