<?php
// 1. CONFIGURATION & ERROR HANDLING
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error && ($error['type'] === E_ERROR || $error['type'] === E_PARSE || $error['type'] === E_CORE_ERROR)) {
        if (ob_get_length()) ob_clean();
        header('Content-Type: application/json');
        echo json_encode(['status' => 'error', 'message' => 'Fatal Error: ' . $error['message'] . ' on line ' . $error['line']]);
        exit;
    }
});

ob_start();
error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING & ~E_DEPRECATED);
ini_set('display_errors', 0);

session_start();
require_once 'system/conn.php'; 

header('Content-Type: application/json');

// 2. AUTH CHECK
if (empty($_SESSION['branch'])) {
    if (ob_get_length()) ob_clean();
    echo json_encode(['status' => 'error', 'message' => 'Session Expired. Please login again.']);
    exit;
}

@set_time_limit(0);
@ini_set('memory_limit', '1024M');
$branch = $_SESSION['branch']; 

try {
    function prepare($conn, $sql) {
        $stmt = $conn->prepare($sql);
        if (!$stmt) throw new Exception("SQL Prepare Failed: " . implode(" ", $conn->errorInfo()));
        return $stmt;
    }
    if (!$conn instanceof PDO) $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // 3. HARD LOCK (CRITICAL FOR CONCURRENCY)
    $stmt = $conn->query("SELECT GET_LOCK('utc_salary_generate', 10)");
    if ($stmt->fetchColumn() != 1) throw new Exception("System Busy: Salary generation is already running.");

    $conn->beginTransaction();

    // 4. DATE LOGIC
    $dateObj = new DateTime('first day of last month');
    $month   = $dateObj->format('m');
    $year    = $dateObj->format('Y');
    $today   = date('Y-m-d');
    $displayDate = $dateObj->format('F Y');

    // 5. PRE-GUARD (STOP IF DATA EXISTS)
    $chkAtt = $conn->prepare("SELECT COUNT(*) FROM salary_attendance WHERE month=? AND year=? AND branch=?");
    $chkAtt->execute([$month, $year, $branch]);
    $chkSal = $conn->prepare("SELECT COUNT(*) FROM emp_salary WHERE month=? AND year=? AND branch=?");
    $chkSal->execute([$month, $year, $branch]);
    if ($chkAtt->fetchColumn() > 0 || $chkSal->fetchColumn() > 0) {
        throw new Exception("Existing salary data found for $displayDate. Please use 'Delete Salary' first.");
    }

    // 6. PRE-FETCH DATA (CACHING FOR SPEED)
    $siteMap = [];
    $stmt = $conn->query("SELECT id, name FROM site");
    while($s = $stmt->fetch(PDO::FETCH_ASSOC)) { $siteMap[$s['id']] = $s['name']; }

    $empMap = [];
    $empStmt = prepare($conn, "SELECT * FROM emp_details WHERE branch=?");
    $empStmt->execute([$branch]);
    while($e = $empStmt->fetch(PDO::FETCH_ASSOC)) { $empMap[$e['e_id']] = $e; }

    if (empty($empMap)) throw new Exception("No Employees found for Branch $branch.");

    // 7. STEP 1: GROUP ATTENDANCE & ONLY-OT LOGIC
    $stmtInsertSalAtt = prepare($conn, "INSERT INTO `salary_attendance` (`emp_id`, `month`, `year`, `t_a`, `b_a`, `o_a`, `block`, `cheque`, `branch`, `maual_advance`, `spc_allow`, `details`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
    $attStmt = prepare($conn, "SELECT * FROM `attendance` WHERE `month`=? AND `year`=? AND `branch`=?");
    $attStmt->execute([$month, $year, $branch]);

    $salAttSession = []; 
    while ($rowss = $attStmt->fetch(PDO::FETCH_ASSOC)) {
        $emp_id = $rowss['emp_id']; 
        if (!isset($salAttSession[$emp_id])) {
            $salAttSession[$emp_id] = ['t_a' => 0, 'b_a' => 0, 'o_a' => 0, 'block' => $rowss['block'], 'cheque' => $rowss['check'], 'maual_advance' => 0, 'spc_allow' => 0, 'details' => ""];
        }
        $curr = &$salAttSession[$emp_id];
        $curr['t_a'] += $rowss['attendance'];
        $curr['maual_advance'] += $rowss['advance_deduction'];
        $curr['spc_allow'] += $rowss['spc_allow'];
        $site_name = $siteMap[$rowss['site']] ?? "Unknown";
        $curr['details'] .= ($curr['details'] == "" ? "" : ", ") . $site_name . "-" . $rowss['attendance'];

        // Process ONLY-OT vs Normal
        if ($rowss['only_ot'] == "yes") {
            $curr['o_a'] += $rowss['attendance'];
        } else {
            if ($curr['b_a'] < 26) {
                $needed = 26 - $curr['b_a'];
                if ($rowss['attendance'] <= $needed) { $curr['b_a'] += $rowss['attendance']; }
                else { $curr['b_a'] = 26; $curr['o_a'] += ($rowss['attendance'] - $needed); }
            } else { $curr['o_a'] += $rowss['attendance']; }
        }
    }

    foreach ($salAttSession as $eid => $d) {
        $stmtInsertSalAtt->execute([$eid, $month, $year, $d['t_a'], $d['b_a'], $d['o_a'], $d['block'], $d['cheque'], $branch, $d['maual_advance'], $d['spc_allow'], $d['details']]);
    }

    // 8. STEP 2: CALCULATE SALARY & ADVANCE LEDGER
    $cal_sa = $conn->query("SELECT * FROM `calculation` LIMIT 1")->fetch(PDO::FETCH_ASSOC);
    $stmtInsSal = prepare($conn, "INSERT INTO `emp_salary` (`name`, `designation`, `ac_no`, `emp_id`, `month`, `year`, `attendance`, `t_at`, `basic_pay`, `hra`, `convyance`, `medical`, `gross_pay`, `pf`, `esic`, `advance`, `tax`, `spc_allow`, `deduction`, `net_pay`, `block`, `cheque`, `branch`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
    $stmtInsAdv = prepare($conn, "INSERT INTO `advance` (`e_id`, `amount`, `date`, `year`, `month`, `manual_balance`, `remaining_amount`, `branch`, `status`) VALUES (?, 0, ?, ?, ?, ?, ?, ?, '1')");

    foreach ($salAttSession as $emp_id => $row) {
        if (!isset($empMap[$emp_id])) continue;
        $row_de = $empMap[$emp_id];
        $salary_x = ($row_de['salary'] > 0) ? round($row_de['salary'] / 26) : 0;
        $cq = ($row_de['bank_ac_no'] == '' || $row_de['bank_ac_no'] == 'NA' || $row['cheque'] == 'yes') ? "yes" : "";

        // Salary Entry
        if ($row['b_a'] > 0) {
            $salary = round($salary_x * $row['b_a']); 
            if (in_array($branch, [4, 14, 41])) { $basic = $salary; $hra = 0; }
            elseif ($branch == 21) { $basic = $salary; $hra = round($basic * 8.33 / 100, 2); }
            else { $basic = round($salary * $cal_sa['basic'] / 100); $hra = round($salary * $cal_sa['hra'] / 100); }

            $pf = ($row_de['pf'] == 'y') ? round($basic * $cal_sa['pf'] / 100) : 0;
            $esi = ($row_de['esi'] == 'y') ? ceil($salary * $cal_sa['esic'] / 100) : 0;
            $tax = ($salary >= 30000) ? 200 : (($salary >= 14000) ? 125 : 0);
            $gross = $basic + $hra + $row['spc_allow'];
            $ded = $row['maual_advance'] + $tax + $pf + $esi;
            $net = round($gross - $ded);

            $stmtInsSal->execute([$row_de['e_name'], $row_de['designation'], $row_de['bank_ac_no'], $emp_id, $month, $year, $row['b_a'], $row['t_a'], $basic, $hra, 0, 0, $gross, $pf, $esi, $row['maual_advance'], $tax, $row['spc_allow'], $ded, $net, $row['block'], $cq, $branch]);
        }

        // Advance Ledger Update (Sequential Running Balance)
        if ($row['maual_advance'] > 0) {
            $advCheck = $conn->prepare("SELECT remaining_amount FROM `advance` WHERE `e_id` = ? AND `branch` = ? ORDER BY `date` DESC, `adv_id` DESC LIMIT 1");
            $advCheck->execute([$emp_id, $branch]);
            $lastRec = $advCheck->fetch(PDO::FETCH_ASSOC);
            $currBal = $lastRec ? $lastRec['remaining_amount'] : 0;
            $newRem = $currBal - $row['maual_advance'];

            $stmtInsAdv->execute([$emp_id, $today, $year, $month, $row['maual_advance'], $newRem, $branch]);
        }
    }

    // 9. STEP 3: CALCULATE OT (SEPARATE BLOCK)
    $stmtInsOT = prepare($conn, "INSERT INTO ot_details (emp_name, Designation, ac_no, emp_id, ot_days, amount, month, year, branch, Hold, cheque) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE amount = VALUES(amount), ot_days = VALUES(ot_days), Hold = VALUES(Hold), cheque = VALUES(cheque)");

    foreach ($salAttSession as $emp_id => $row) {
        if (!isset($empMap[$emp_id]) || $row['o_a'] <= 0) continue;
        $row_de = $empMap[$emp_id];
        $salary_x = ($row_de['salary'] > 0) ? round($row_de['salary'] / 26) : 0;
        $ot_amt = round($salary_x * $row['o_a']);
        $cq_ot = ($row_de['bank_ac_no'] == '' || $row_de['bank_ac_no'] == 'NA' || $row['cheque'] == 'yes') ? "yes" : "";

        $stmtInsOT->execute([$row_de['e_name'], $row_de['designation'], $row_de['bank_ac_no'], $emp_id, $row['o_a'], $ot_amt, $month, $year, $branch, $row['block'], $cq_ot]);
    }

    $conn->commit();
    $conn->query("SELECT RELEASE_LOCK('utc_salary_generate')");
    echo json_encode(['status' => 'success', 'message' => "Payroll Generated: Salaries, OT, and Ledger updated."]);

} catch (Throwable $e) {
    if (isset($conn) && $conn->inTransaction()) $conn->rollBack();
    if (isset($conn)) { try { $conn->query("SELECT RELEASE_LOCK('utc_salary_generate')"); } catch (Throwable $t) {} }
    if (ob_get_length()) ob_clean();
    echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
    exit;
}