<?php
// ============================================================
//  MJPOS – Payroll Controller
// ============================================================
class PayrollController extends Controller
{
    // ── Dashboard ────────────────────────────────────────────
    public function index(): void
    {
        Auth::requirePermission('payroll.view');

        $periods = Database::fetchAll(
            "SELECT pp.*, COUNT(pr.id) AS emp_count,
                    COALESCE(SUM(pr.net_salary),0) AS total_net,
                    COUNT(CASE WHEN pr.payment_status='paid' THEN 1 END) AS paid_count
             FROM payroll_periods pp
             LEFT JOIN payroll_records pr ON pr.period_id = pp.id
             GROUP BY pp.id ORDER BY pp.year DESC, pp.month DESC LIMIT 12"
        );

        $stats = Database::fetchOne(
            "SELECT COUNT(*) AS total_emp,
                    COUNT(CASE WHEN status='active' THEN 1 END) AS active_emp,
                    COALESCE(SUM(CASE WHEN status='active' THEN basic_salary END),0) AS monthly_payroll
             FROM employees"
        );

        $currentPeriod = Database::fetchOne(
            "SELECT pp.*, COALESCE(SUM(pr.net_salary),0) AS total_net,
                    COUNT(pr.id) AS processed
             FROM payroll_periods pp
             LEFT JOIN payroll_records pr ON pr.period_id=pp.id
             WHERE pp.month=? AND pp.year=?
             GROUP BY pp.id",
            [(int)date('n'), (int)date('Y')]
        );

        $pageTitle  = 'Payroll Management';
        $breadcrumb = [['label' => 'Payroll']];
        ob_start(); require APP_PATH.'/views/payroll/index.php';
        $content = ob_get_clean();
        require APP_PATH.'/views/layouts/main.php';
    }

    // ── Employees list ────────────────────────────────────────
    public function employees(): void
    {
        Auth::requirePermission('payroll.employees');

        $search = trim($this->get('search',''));
        $dept   = Security::strip($this->get('dept',''));
        $status = $this->get('status','active');

        $where  = ['1=1']; $params = [];
        if ($search) { $where[]='(e.full_name LIKE ? OR e.emp_code LIKE ? OR e.designation LIKE ?)'; $params=array_merge($params,["%$search%","%$search%","%$search%"]); }
        if ($dept)   { $where[]='e.department=?'; $params[]=$dept; }
        if ($status!=='all') { $where[]='e.status=?'; $params[]=$status; }

        $employees = Database::fetchAll(
            "SELECT e.*, b.name AS branch_name
             FROM employees e
             LEFT JOIN branches b ON b.id=e.branch_id
             WHERE ".implode(' AND ',$where)."
             ORDER BY e.full_name ASC", $params
        );

        $departments = Database::fetchAll(
            "SELECT DISTINCT department FROM employees WHERE department IS NOT NULL AND department!='' ORDER BY department"
        );

        $pageTitle  = 'Employees';
        $breadcrumb = [['label'=>'Payroll','url'=>APP_URL.'/payroll'],['label'=>'Employees']];
        ob_start(); require APP_PATH.'/views/payroll/employees.php';
        $content = ob_get_clean();
        require APP_PATH.'/views/layouts/main.php';
    }

    // ── Add employee form ─────────────────────────────────────
    public function addEmployee(): void
    {
        Auth::requirePermission('payroll.employees');
        $employee   = null;
        $components = Database::fetchAll("SELECT * FROM salary_components WHERE status='active' ORDER BY type,name");
        $branches   = Database::fetchAll("SELECT id,name FROM branches WHERE status='active' ORDER BY is_main DESC,name");
        $users      = Database::fetchAll("SELECT id,name FROM users WHERE status='active' ORDER BY name");
        $pageTitle  = 'Add Employee';
        $breadcrumb = [['label'=>'Payroll','url'=>APP_URL.'/payroll'],['label'=>'Employees','url'=>APP_URL.'/payroll/employees'],['label'=>'Add']];
        ob_start(); require APP_PATH.'/views/payroll/employee_form.php';
        $content = ob_get_clean();
        require APP_PATH.'/views/layouts/main.php';
    }

    public function storeEmployee(): void
    {
        Auth::requirePermission('payroll.employees');
        Auth::requireCsrf();

        $code = strtoupper(Security::strip($this->post('emp_code','')));
        if (!$code) {
            $lastId = (int)Database::fetchColumn("SELECT MAX(id) FROM employees") + 1;
            $code   = 'EMP'.str_pad($lastId, 4, '0', STR_PAD_LEFT);
        }

        Database::execute(
            "INSERT INTO employees (emp_code,full_name,phone,email,nic,designation,department,
             branch_id,join_date,basic_salary,pay_type,bank_name,bank_account,bank_branch,status,user_id)
             VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
            [
                $code,
                Security::strip($this->post('full_name','')),
                Security::strip($this->post('phone','')),
                Security::strip($this->post('email','')),
                Security::strip($this->post('nic','')),
                Security::strip($this->post('designation','')),
                Security::strip($this->post('department','')),
                (int)$this->post('branch_id',1),
                $this->post('join_date', date('Y-m-d')),
                (float)$this->post('basic_salary',0),
                Security::enum($this->post('pay_type','monthly'),['monthly','daily','hourly'],'monthly'),
                Security::strip($this->post('bank_name','')),
                Security::strip($this->post('bank_account','')),
                Security::strip($this->post('bank_branch','')),
                Security::enum($this->post('status','active'),['active','inactive','terminated'],'active'),
                $this->post('user_id') ?: null,
            ]
        );

        $empId = (int)Database::fetchColumn('SELECT LAST_INSERT_ID()');

        // Save components
        $compIds  = (array)$this->post('component_id',[]);
        $compAmts = (array)$this->post('component_amount',[]);
        foreach ($compIds as $i => $cid) {
            if ($cid && isset($compAmts[$i]) && (float)$compAmts[$i] > 0) {
                Database::execute(
                    'INSERT INTO employee_components (employee_id,component_id,amount) VALUES (?,?,?)',
                    [$empId, (int)$cid, (float)$compAmts[$i]]
                );
            }
        }

        Auth::logAudit(Auth::id(),'employee_create','employees',"Added employee: {$code}");
        redirectWith(APP_URL.'/payroll/employees','success',"Employee {$code} added.");
    }

    public function editEmployee(string $id): void
    {
        Auth::requirePermission('payroll.employees');
        $employee = Database::fetchOne('SELECT * FROM employees WHERE id=?',[(int)$id]);
        if (!$employee) { redirectWith(APP_URL.'/payroll/employees','error','Not found.'); return; }
        $empComponents = Database::fetchAll('SELECT * FROM employee_components WHERE employee_id=?',[(int)$id]);
        $empCompMap = [];
        foreach($empComponents as $ec) $empCompMap[$ec['component_id']]=$ec['amount'];
        $components = Database::fetchAll("SELECT * FROM salary_components WHERE status='active' ORDER BY type,name");
        $branches   = Database::fetchAll("SELECT id,name FROM branches WHERE status='active' ORDER BY is_main DESC,name");
        $users      = Database::fetchAll("SELECT id,name FROM users WHERE status='active' ORDER BY name");
        $pageTitle  = 'Edit Employee: '.$employee['full_name'];
        $breadcrumb = [['label'=>'Payroll','url'=>APP_URL.'/payroll'],['label'=>'Employees','url'=>APP_URL.'/payroll/employees'],['label'=>'Edit']];
        ob_start(); require APP_PATH.'/views/payroll/employee_form.php';
        $content = ob_get_clean();
        require APP_PATH.'/views/layouts/main.php';
    }

    public function updateEmployee(string $id): void
    {
        Auth::requirePermission('payroll.employees');
        Auth::requireCsrf();
        $empId = (int)$id;
        Database::execute(
            "UPDATE employees SET full_name=?,phone=?,email=?,nic=?,designation=?,department=?,
             branch_id=?,join_date=?,basic_salary=?,pay_type=?,bank_name=?,bank_account=?,
             bank_branch=?,status=?,user_id=? WHERE id=?",
            [
                Security::strip($this->post('full_name','')),
                Security::strip($this->post('phone','')),
                Security::strip($this->post('email','')),
                Security::strip($this->post('nic','')),
                Security::strip($this->post('designation','')),
                Security::strip($this->post('department','')),
                (int)$this->post('branch_id',1),
                $this->post('join_date',date('Y-m-d')),
                (float)$this->post('basic_salary',0),
                Security::enum($this->post('pay_type','monthly'),['monthly','daily','hourly'],'monthly'),
                Security::strip($this->post('bank_name','')),
                Security::strip($this->post('bank_account','')),
                Security::strip($this->post('bank_branch','')),
                Security::enum($this->post('status','active'),['active','inactive','terminated'],'active'),
                $this->post('user_id') ?: null,
                $empId,
            ]
        );
        Database::execute('DELETE FROM employee_components WHERE employee_id=?',[$empId]);
        $compIds  = (array)$this->post('component_id',[]);
        $compAmts = (array)$this->post('component_amount',[]);
        foreach ($compIds as $i => $cid) {
            if ($cid && isset($compAmts[$i]) && (float)$compAmts[$i] > 0) {
                Database::execute(
                    'INSERT INTO employee_components (employee_id,component_id,amount) VALUES (?,?,?)',
                    [$empId,(int)$cid,(float)$compAmts[$i]]
                );
            }
        }
        redirectWith(APP_URL.'/payroll/employees','success','Employee updated.');
    }

    // ── Payroll Periods ───────────────────────────────────────
    public function createPeriod(): void
    {
        Auth::requirePermission('payroll.manage');
        Auth::requireCsrf();

        $month = (int)$this->post('month', date('n'));
        $year  = (int)$this->post('year',  date('Y'));

        $exists = Database::fetchColumn('SELECT id FROM payroll_periods WHERE month=? AND year=?',[$month,$year]);
        if ($exists) { redirectWith(APP_URL.'/payroll','error','Period already exists.'); return; }

        $start = date('Y-m-01', mktime(0,0,0,$month,1,$year));
        $end   = date('Y-m-t',  mktime(0,0,0,$month,1,$year));
        $name  = date('F Y',    mktime(0,0,0,$month,1,$year));

        Database::execute(
            'INSERT INTO payroll_periods (period_name,month,year,start_date,end_date,status,created_by) VALUES (?,?,?,?,?,?,?)',
            [$name,$month,$year,$start,$end,'draft',Auth::id()]
        );
        $periodId = (int)Database::fetchColumn('SELECT LAST_INSERT_ID()');
        redirectWith(APP_URL.'/payroll/process/'.$periodId,'success',"Period \"{$name}\" created. Now process payroll.");
    }

    // ── Process payroll for a period ─────────────────────────
    public function process(string $id): void
    {
        Auth::requirePermission('payroll.view');
        $period = Database::fetchOne('SELECT * FROM payroll_periods WHERE id=?',[(int)$id]);
        if (!$period) { redirectWith(APP_URL.'/payroll','error','Period not found.'); return; }

        $employees = Database::fetchAll(
            "SELECT e.*,
                    COALESCE(pr.id,0) AS record_id,
                    pr.net_salary,pr.payment_status,pr.gross_salary,
                    pr.total_allowances,pr.total_deductions,pr.present_days
             FROM employees e
             LEFT JOIN payroll_records pr ON pr.employee_id=e.id AND pr.period_id=?
             WHERE e.status='active' ORDER BY e.full_name", [(int)$id]
        );

        $pageTitle  = 'Process Payroll — '.$period['period_name'];
        $breadcrumb = [['label'=>'Payroll','url'=>APP_URL.'/payroll'],['label'=>$period['period_name']]];
        ob_start(); require APP_PATH.'/views/payroll/process.php';
        $content = ob_get_clean();
        require APP_PATH.'/views/layouts/main.php';
    }

    // ── Save payroll records ──────────────────────────────────
    public function savePayroll(string $id): void
    {
        Auth::requirePermission('payroll.manage');
        Auth::requireCsrf();

        $periodId = (int)$id;
        $period   = Database::fetchOne('SELECT * FROM payroll_periods WHERE id=?',[$periodId]);
        if (!$period || $period['status']==='paid') {
            redirectWith(APP_URL.'/payroll','error','Cannot modify paid period.');
            return;
        }

        $empIds      = (array)$this->post('employee_id',[]);
        $presentDays = (array)$this->post('present_days',[]);
        $otHours     = (array)$this->post('overtime_hours',[]);
        $otRates     = (array)$this->post('overtime_rate',[]);
        $pmtMethods  = (array)$this->post('payment_method',[]);
        $notes       = (array)$this->post('notes',[]);

        foreach ($empIds as $i => $empId) {
            $emp = Database::fetchOne('SELECT * FROM employees WHERE id=?',[(int)$empId]);
            if (!$emp) continue;

            $workingDays = 26;
            $present     = min((float)($presentDays[$i]??$workingDays), $workingDays);
            $otHrs       = max(0,(float)($otHours[$i]??0));
            $otRate      = max(0,(float)($otRates[$i]??0));
            $otAmt       = $otHrs * $otRate;
            $dailyRate   = $emp['pay_type']==='monthly' ? $emp['basic_salary']/$workingDays : $emp['basic_salary'];
            $earnedBasic = $dailyRate * $present;

            // Get components
            $comps = Database::fetchAll(
                'SELECT ec.amount, sc.name, sc.type, sc.calc_type, ec.component_id
                 FROM employee_components ec
                 JOIN salary_components sc ON sc.id=ec.component_id
                 WHERE ec.employee_id=?', [(int)$empId]
            );

            // Advances for this period
            $advances = (float)Database::fetchColumn(
                'SELECT COALESCE(SUM(amount),0) FROM salary_advances
                 WHERE employee_id=? AND deduct_month=? AND deduct_year=? AND status=\'pending\'',
                [(int)$empId, $period['month'], $period['year']]
            );

            $totalAllowances = $otAmt;
            $totalDeductions = 0;
            $epfEmployee     = round($earnedBasic * 0.08, 2);
            $epfEmployer     = round($earnedBasic * 0.12, 2);
            $etf             = round($earnedBasic * 0.03, 2);

            $compLines = [];
            foreach ($comps as $c) {
                $amt = $c['calc_type']==='percentage'
                    ? round($earnedBasic * $c['amount'] / 100, 2)
                    : (float)$c['amount'];
                if ($c['type']==='allowance') $totalAllowances += $amt;
                else                           $totalDeductions += $amt;
                $compLines[] = ['component_id'=>$c['component_id'],'name'=>$c['name'],'type'=>$c['type'],'amount'=>$amt];
            }
            if ($advances > 0) {
                $totalDeductions += $advances;
                $compLines[] = ['component_id'=>null,'name'=>'Salary Advance','type'=>'deduction','amount'=>$advances];
            }

            $grossSalary = $earnedBasic + $totalAllowances;
            $netSalary   = max(0, $grossSalary - $totalDeductions - $epfEmployee);

            // Upsert payroll record
            $existing = Database::fetchColumn(
                'SELECT id FROM payroll_records WHERE period_id=? AND employee_id=?',[$periodId,(int)$empId]
            );
            if ($existing) {
                Database::execute(
                    "UPDATE payroll_records SET basic_salary=?,working_days=?,present_days=?,
                     overtime_hours=?,overtime_rate=?,overtime_amount=?,gross_salary=?,
                     total_allowances=?,total_deductions=?,epf_employee=?,epf_employer=?,etf=?,
                     net_salary=?,payment_method=?,notes=? WHERE id=?",
                    [$emp['basic_salary'],$workingDays,$present,$otHrs,$otRate,$otAmt,$grossSalary,
                     $totalAllowances,$totalDeductions,$epfEmployee,$epfEmployer,$etf,$netSalary,
                     $pmtMethods[$i]??'bank_transfer',$notes[$i]??'',(int)$existing]
                );
                Database::execute('DELETE FROM payroll_record_components WHERE record_id=?',[(int)$existing]);
                $recId = (int)$existing;
            } else {
                Database::execute(
                    "INSERT INTO payroll_records (period_id,employee_id,basic_salary,working_days,
                     present_days,overtime_hours,overtime_rate,overtime_amount,gross_salary,
                     total_allowances,total_deductions,epf_employee,epf_employer,etf,net_salary,
                     payment_method,notes)
                     VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
                    [$periodId,(int)$empId,$emp['basic_salary'],$workingDays,$present,$otHrs,$otRate,
                     $otAmt,$grossSalary,$totalAllowances,$totalDeductions,$epfEmployee,$epfEmployer,
                     $etf,$netSalary,$pmtMethods[$i]??'bank_transfer',$notes[$i]??'']
                );
                $recId = (int)Database::fetchColumn('SELECT LAST_INSERT_ID()');
            }

            foreach ($compLines as $cl) {
                Database::execute(
                    'INSERT INTO payroll_record_components (record_id,component_id,name,type,amount) VALUES (?,?,?,?,?)',
                    [$recId,$cl['component_id']??null,$cl['name'],$cl['type'],$cl['amount']]
                );
            }

            // Mark advances as deducted
            if ($advances > 0) {
                Database::execute(
                    "UPDATE salary_advances SET status='deducted'
                     WHERE employee_id=? AND deduct_month=? AND deduct_year=? AND status='pending'",
                    [(int)$empId,$period['month'],$period['year']]
                );
            }
        }

        Database::execute("UPDATE payroll_periods SET status='processing' WHERE id=?",[$periodId]);
        Auth::logAudit(Auth::id(),'payroll_process','payroll_periods',"Processed: {$period['period_name']}");
        redirectWith(APP_URL.'/payroll/process/'.$periodId,'success','Payroll calculated. Review and approve.');
    }

    // ── Approve period ────────────────────────────────────────
    public function approve(string $id): void
    {
        Auth::requirePermission('payroll.approve');
        Auth::requireCsrf();
        $periodId = (int)$id;
        Database::execute(
            "UPDATE payroll_periods SET status='approved',approved_by=?,approved_at=NOW() WHERE id=?",
            [Auth::id(),$periodId]
        );
        redirectWith(APP_URL.'/payroll/process/'.$periodId,'success','Payroll approved. Ready for payment.');
    }

    // ── Mark as paid ──────────────────────────────────────────
    public function markPaid(string $id): void
    {
        Auth::requirePermission('payroll.approve');
        Auth::requireCsrf();
        $periodId = (int)$id;
        Database::execute(
            "UPDATE payroll_records SET payment_status='paid',paid_at=NOW() WHERE period_id=?",[$periodId]
        );
        Database::execute("UPDATE payroll_periods SET status='paid' WHERE id=?",[$periodId]);
        Auth::logAudit(Auth::id(),'payroll_paid','payroll_periods',"Marked paid: period #{$periodId}");
        redirectWith(APP_URL.'/payroll/process/'.$periodId,'success','All salaries marked as paid.');
    }

    // ── Pay slip (single employee) ────────────────────────────
    public function payslip(string $id): void
    {
        Auth::requirePermission('payroll.view');
        $record = Database::fetchOne(
            "SELECT pr.*, e.full_name, e.emp_code, e.designation, e.department,
                    e.bank_name, e.bank_account,
                    pp.period_name, pp.month, pp.year, pp.start_date, pp.end_date,
                    b.name AS branch_name
             FROM payroll_records pr
             JOIN employees e  ON e.id=pr.employee_id
             JOIN payroll_periods pp ON pp.id=pr.period_id
             LEFT JOIN branches b ON b.id=e.branch_id
             WHERE pr.id=?", [(int)$id]
        );
        if (!$record) { redirectWith(APP_URL.'/payroll','error','Record not found.'); return; }

        $components = Database::fetchAll(
            'SELECT * FROM payroll_record_components WHERE record_id=? ORDER BY type DESC',[(int)$id]
        );

        $pageTitle  = 'Pay Slip — '.$record['full_name'];
        ob_start(); require APP_PATH.'/views/payroll/payslip.php';
        $content = ob_get_clean();
        require APP_PATH.'/views/layouts/main.php';
    }

    // ── Salary advances ───────────────────────────────────────
    public function advances(): void
    {
        Auth::requirePermission('payroll.manage');
        $advances = Database::fetchAll(
            "SELECT sa.*, e.full_name, e.emp_code
             FROM salary_advances sa JOIN employees e ON e.id=sa.employee_id
             ORDER BY sa.advance_date DESC LIMIT 50"
        );
        $employees = Database::fetchAll("SELECT id,full_name,emp_code FROM employees WHERE status='active' ORDER BY full_name");
        $pageTitle  = 'Salary Advances';
        $breadcrumb = [['label'=>'Payroll','url'=>APP_URL.'/payroll'],['label'=>'Advances']];
        ob_start(); require APP_PATH.'/views/payroll/advances.php';
        $content = ob_get_clean();
        require APP_PATH.'/views/layouts/main.php';
    }

    public function storeAdvance(): void
    {
        Auth::requirePermission('payroll.manage');
        Auth::requireCsrf();
        Database::execute(
            'INSERT INTO salary_advances (employee_id,amount,advance_date,reason,deduct_month,deduct_year,created_by)
             VALUES (?,?,?,?,?,?,?)',
            [(int)$this->post('employee_id'), (float)$this->post('amount'),
             $this->post('advance_date',date('Y-m-d')), Security::strip($this->post('reason','')),
             (int)$this->post('deduct_month', date('n')),
             (int)$this->post('deduct_year',  date('Y')), Auth::id()]
        );
        redirectWith(APP_URL.'/payroll/advances','success','Advance recorded.');
    }

    // ── Reports ───────────────────────────────────────────────
    public function report(): void
    {
        Auth::requirePermission('payroll.reports');
        $year = (int)$this->get('year', date('Y'));

        $monthly = Database::fetchAll(
            "SELECT pp.month, pp.period_name, pp.status,
                    COUNT(pr.id) AS emp_count,
                    COALESCE(SUM(pr.gross_salary),0) AS total_gross,
                    COALESCE(SUM(pr.net_salary),0)   AS total_net,
                    COALESCE(SUM(pr.epf_employee),0) AS total_epf_emp,
                    COALESCE(SUM(pr.epf_employer),0) AS total_epf_er,
                    COALESCE(SUM(pr.etf),0)          AS total_etf
             FROM payroll_periods pp
             LEFT JOIN payroll_records pr ON pr.period_id=pp.id
             WHERE pp.year=? GROUP BY pp.id ORDER BY pp.month ASC", [$year]
        );

        $employees = Database::fetchAll(
            "SELECT e.full_name, e.emp_code, e.designation, e.department,
                    COUNT(pr.id) AS months_paid,
                    COALESCE(SUM(pr.net_salary),0) AS total_net
             FROM employees e
             LEFT JOIN payroll_records pr ON pr.employee_id=e.id
             LEFT JOIN payroll_periods pp ON pp.id=pr.period_id AND pp.year=?
             WHERE e.status='active'
             GROUP BY e.id ORDER BY e.full_name", [$year]
        );

        $pageTitle  = 'Payroll Report '.$year;
        $breadcrumb = [['label'=>'Payroll','url'=>APP_URL.'/payroll'],['label'=>'Reports']];
        ob_start(); require APP_PATH.'/views/payroll/report.php';
        $content = ob_get_clean();
        require APP_PATH.'/views/layouts/main.php';
    }

    // ── Toggle employee status ────────────────────────────────
    public function toggleEmployee(string $id): void
    {
        Auth::requirePermission('payroll.employees');
        Auth::requireCsrf();
        $emp = Database::fetchOne('SELECT id,status,full_name FROM employees WHERE id=?',[(int)$id]);
        if (!$emp) { redirectWith(APP_URL.'/payroll/employees','error','Employee not found.'); return; }
        $newStatus = $emp['status']==='active' ? 'inactive' : 'active';
        Database::execute('UPDATE employees SET status=? WHERE id=?',[$newStatus,(int)$id]);
        redirectWith(APP_URL.'/payroll/employees','success',
            e($emp['full_name']).' marked as '.ucfirst($newStatus).'.');
    }

    // ── Delete employee ───────────────────────────────────────
    public function deleteEmployee(string $id): void
    {
        Auth::requirePermission('payroll.employees');
        Auth::requireCsrf();
        $empId = (int)$id;
        $hasPayroll = (int)Database::fetchColumn(
            'SELECT COUNT(*) FROM payroll_records WHERE employee_id=?',[$empId]
        );
        if ($hasPayroll) {
            redirectWith(APP_URL.'/payroll/employees','error',
                'Cannot delete — employee has payroll history. Set status to Inactive instead.');
            return;
        }
        Database::execute('DELETE FROM employee_components WHERE employee_id=?',[$empId]);
        Database::execute('DELETE FROM salary_advances WHERE employee_id=?',[$empId]);
        Database::execute('DELETE FROM employees WHERE id=?',[$empId]);
        redirectWith(APP_URL.'/payroll/employees','success','Employee deleted.');
    }

    // ── View employee profile ─────────────────────────────────
    public function viewEmployee(string $id): void
    {
        Auth::requirePermission('payroll.view');
        $employee = Database::fetchOne(
            'SELECT e.*,b.name AS branch_name FROM employees e
             LEFT JOIN branches b ON b.id=e.branch_id WHERE e.id=?',[(int)$id]
        );
        if (!$employee) { redirectWith(APP_URL.'/payroll/employees','error','Not found.'); return; }

        $components = Database::fetchAll(
            'SELECT ec.amount, sc.name, sc.type
             FROM employee_components ec
             JOIN salary_components sc ON sc.id=ec.component_id
             WHERE ec.employee_id=? ORDER BY sc.type DESC,sc.name',[(int)$id]
        );
        $payrollHistory = Database::fetchAll(
            'SELECT pr.*,pp.period_name FROM payroll_records pr
             JOIN payroll_periods pp ON pp.id=pr.period_id
             WHERE pr.employee_id=? ORDER BY pp.year DESC,pp.month DESC LIMIT 12',[(int)$id]
        );
        $advances = Database::fetchAll(
            'SELECT * FROM salary_advances WHERE employee_id=? ORDER BY advance_date DESC LIMIT 6',[(int)$id]
        );

        $pageTitle  = 'Employee: '.$employee['full_name'];
        $breadcrumb = [
            ['label'=>'Payroll','url'=>APP_URL.'/payroll'],
            ['label'=>'Employees','url'=>APP_URL.'/payroll/employees'],
            ['label'=>$employee['full_name']],
        ];
        ob_start(); require APP_PATH.'/views/payroll/employee_view.php';
        $content = ob_get_clean();
        require APP_PATH.'/views/layouts/main.php';
    }
}