<?php
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/db.php';
require_login();
header('Content-Type: application/json');

$mysqli = db();
$action = $_GET['action'] ?? $_POST['action'] ?? 'list';

// Ensure journal_entries header table exists
$mysqli->query("CREATE TABLE IF NOT EXISTS journal_entries (
    id              INT AUTO_INCREMENT PRIMARY KEY,
    voucher_number  VARCHAR(50)  NOT NULL UNIQUE,
    entry_date      DATE         NOT NULL,
    entry_type      ENUM('Simple','Compound','Adjusting','Closing','Opening','Reversing') NOT NULL DEFAULT 'Simple',
    narration       TEXT         NOT NULL,
    reference       VARCHAR(100) DEFAULT NULL,
    status          ENUM('Draft','Posted','Reversed') NOT NULL DEFAULT 'Draft',
    total_debit     DECIMAL(15,2) NOT NULL DEFAULT 0,
    total_credit    DECIMAL(15,2) NOT NULL DEFAULT 0,
    created_by      INT          DEFAULT NULL,
    posted_by       INT          DEFAULT NULL,
    posted_at       TIMESTAMP    NULL,
    reversed_by     INT          DEFAULT NULL,
    reversed_at     TIMESTAMP    NULL,
    reversal_of     INT          DEFAULT NULL,
    created_at      TIMESTAMP    DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB");

// Lines table (debit/credit lines per journal entry)
$mysqli->query("CREATE TABLE IF NOT EXISTS journal_entry_lines (
    id              INT AUTO_INCREMENT PRIMARY KEY,
    journal_id      INT          NOT NULL,
    account_head    VARCHAR(150) NOT NULL,
    sub_account_head VARCHAR(150) DEFAULT NULL,
    account_code    VARCHAR(20)  DEFAULT NULL,
    debit_amount    DECIMAL(15,2) NOT NULL DEFAULT 0,
    credit_amount   DECIMAL(15,2) NOT NULL DEFAULT 0,
    cost_center     VARCHAR(100) DEFAULT NULL,
    line_narration  VARCHAR(255) DEFAULT NULL,
    sort_order      INT          DEFAULT 0,
    FOREIGN KEY (journal_id) REFERENCES journal_entries(id) ON DELETE CASCADE
) ENGINE=InnoDB");
try { $mysqli->query("ALTER TABLE journal_entry_lines ADD COLUMN IF NOT EXISTS sub_account_head VARCHAR(150) DEFAULT NULL"); } catch(Exception $e){}

// ── Helpers ───────────────────────────────────────────────────────────────────
function generateJournalVoucher($mysqli, $date) {
    $prefix = 'JNL';
    $y  = date('Y', strtotime($date));
    $md = date('md', strtotime($date));
    $r  = $mysqli->query("SELECT COUNT(*)+1 n FROM journal_entries WHERE YEAR(entry_date)='$y'");
    $seq = str_pad((int)$r->fetch_assoc()['n'], 4, '0', STR_PAD_LEFT);
    return "$prefix/$y/$md/$seq";
}

function postToGLAndTransaction($mysqli, $journalId) {
    $j = $mysqli->query("SELECT * FROM journal_entries WHERE id=$journalId")->fetch_assoc();
    if (!$j) return ['success'=>false,'message'=>'Journal not found'];

    $lines = [];
    $r = $mysqli->query("SELECT * FROM journal_entry_lines WHERE journal_id=$journalId ORDER BY sort_order");
    while ($row = $r->fetch_assoc()) $lines[] = $row;

    if (empty($lines)) return ['success'=>false,'message'=>'No lines found'];

    $totalDr = array_sum(array_column($lines,'debit_amount'));
    $totalCr = array_sum(array_column($lines,'credit_amount'));
    if (round($totalDr,2) !== round($totalCr,2))
        return ['success'=>false,'message'=>'Debits ('.number_format($totalDr,2).') ≠ Credits ('.number_format($totalCr,2).')'];

    $mysqli->begin_transaction();
    try {
        // Create transactions record
        $userId = $_SESSION['user']['id'] ?? null;
        $stmt = $mysqli->prepare(
            "INSERT INTO transactions
             (voucher_number, transaction_date, transaction_type, account_head, amount,
              narration, document_reference, entered_by, approval_status, is_cancelled)
             VALUES (?,?,'Journal',?,?,?,?,?,'pending',0)"
        );
        $ah  = $lines[0]['account_head'];
        $amt = $totalDr;
        $stmt->bind_param('sssdssi',
            $j['voucher_number'], $j['entry_date'],
            $ah, $amt, $j['narration'], $j['reference'], $userId
        );
        $stmt->execute();
        $txId = $mysqli->insert_id;
        $stmt->close();

        // Insert gl_entries for each line
        $glStmt = $mysqli->prepare(
            "INSERT INTO gl_entries
             (transaction_id, voucher_number, entry_date, account_name, account_code,
              debit_amount, credit_amount, narration, cost_center, created_by)
             VALUES (?,?,?,?,?,?,?,?,?,?)"
        );
        foreach ($lines as $line) {
            $glStmt->bind_param('issssddssi',
                $txId, $j['voucher_number'], $j['entry_date'],
                $line['account_head'], $line['account_code'],
                $line['debit_amount'], $line['credit_amount'],
                $line['line_narration'] ?: $j['narration'],
                $line['cost_center'], $userId
            );
            $glStmt->execute();
        }
        $glStmt->close();

        // Mark journal as Posted
        $mysqli->prepare("UPDATE journal_entries SET status='Posted', posted_by=?, posted_at=NOW(), total_debit=?, total_credit=? WHERE id=?")
               ->execute_with_close([$userId, $totalDr, $totalCr, $journalId]);

        $mysqli->commit();
        return ['success'=>true,'transaction_id'=>$txId,'message'=>'Journal posted successfully'];
    } catch (Exception $e) {
        $mysqli->rollback();
        return ['success'=>false,'message'=>$e->getMessage()];
    }
}

// Helper for prepared exec
mysqli::$execute_with_close ?? null; // silence

// ── Actions ───────────────────────────────────────────────────────────────────
switch ($action) {

    case 'list':
        $status    = trim($_GET['status'] ?? '');
        $type      = trim($_GET['entry_type'] ?? '');
        $date_from = trim($_GET['date_from'] ?? '');
        $date_to   = trim($_GET['date_to'] ?? '');
        $search    = trim($_GET['search'] ?? '');

        $where = ['1']; $params = []; $types = '';
        if ($status)    { $where[] = 'j.status=?';          $params[]=$status;    $types.='s'; }
        if ($type)      { $where[] = 'j.entry_type=?';      $params[]=$type;      $types.='s'; }
        if ($date_from) { $where[] = 'j.entry_date>=?';     $params[]=$date_from; $types.='s'; }
        if ($date_to)   { $where[] = 'j.entry_date<=?';     $params[]=$date_to;   $types.='s'; }
        if ($search)    {
            $where[] = '(j.voucher_number LIKE ? OR j.narration LIKE ? OR j.reference LIKE ?)';
            $s='%'.$search.'%'; $params=array_merge($params,[$s,$s,$s]); $types.='sss';
        }

        $sql = "SELECT j.*, u.full_name AS created_by_name
                FROM journal_entries j
                LEFT JOIN employees u ON u.id=j.created_by
                WHERE ".implode(' AND ',$where)."
                ORDER BY j.entry_date DESC, j.id DESC";

        if ($params) {
            $stmt=$mysqli->prepare($sql);
            $stmt->bind_param($types,...$params);
            $stmt->execute();
            $res=$stmt->get_result();
        } else { $res=$mysqli->query($sql); }

        $data=[];
        while($row=$res->fetch_assoc()) $data[]=$row;
        json_response(['data'=>$data]);
        break;

    case 'get':
        $id=(int)($_GET['id']??0);
        if(!$id) json_response(['message'=>'ID required'],400);
        $j=$mysqli->query("SELECT * FROM journal_entries WHERE id=$id")->fetch_assoc();
        if(!$j) json_response(['message'=>'Not found'],404);
        $lines=[];
        $r=$mysqli->query("SELECT * FROM journal_entry_lines WHERE journal_id=$id ORDER BY sort_order");
        while($row=$r->fetch_assoc()) $lines[]=$row;
        json_response(['data'=>$j,'lines'=>$lines]);
        break;

    case 'create':
        if (!has_role(['admin','super_admin','accountant','finance_manager']))
            json_response(['message'=>'Access denied'],403);
        if (!validate_csrf($_POST['csrf']??'')) json_response(['message'=>'Invalid CSRF'],400);

        $date      = trim($_POST['entry_date']??'');
        $type      = trim($_POST['entry_type']??'Simple');
        $narration = trim($_POST['narration']??'');
        $reference = trim($_POST['reference']??'');
        $asDraft   = ($_POST['save_as']??'draft') === 'draft';
        $userId    = $_SESSION['user']['id'] ?? null;

        if (!$date || !$narration) json_response(['message'=>'Date and narration required'],400);

        // Parse lines: lines[0][account_head], lines[0][debit], lines[0][credit], etc.
        $rawLines = $_POST['lines'] ?? [];
        if (count($rawLines) < 2) json_response(['message'=>'At least 2 lines required'],400);

        $totalDr=0; $totalCr=0;
        $cleanLines=[];
        foreach ($rawLines as $i=>$l) {
            $ah  = trim($l['account_head']??'');
            $dr  = round((float)($l['debit']??0),2);
            $cr  = round((float)($l['credit']??0),2);
            if (!$ah) continue;
            if ($dr==0 && $cr==0) continue;
            $totalDr += $dr; $totalCr += $cr;
            $cleanLines[] = [
                'account_head'    => $ah,
                'sub_account_head'=> trim($l['sub_account_head']??''),
                'account_code'    => trim($l['account_code']??''),
                'debit_amount'    => $dr,
                'credit_amount'   => $cr,
                'cost_center'     => trim($l['cost_center']??''),
                'line_narration'  => trim($l['line_narration']??''),
                'sort_order'      => $i,
            ];
        }

        if (count($cleanLines) < 2) json_response(['message'=>'At least 2 valid lines required'],400);
        if (!$asDraft && round($totalDr,2) !== round($totalCr,2))
            json_response(['message'=>'Debits ('.number_format($totalDr,2).') must equal Credits ('.number_format($totalCr,2).')'],400);

        $voucher = generateJournalVoucher($mysqli, $date);
        $status  = $asDraft ? 'Draft' : 'Posted';

        $mysqli->begin_transaction();
        try {
            $stmt=$mysqli->prepare(
                "INSERT INTO journal_entries (voucher_number,entry_date,entry_type,narration,reference,status,total_debit,total_credit,created_by)
                 VALUES (?,?,?,?,?,?,?,?,?)"
            );
            $stmt->bind_param('ssssssddi',$voucher,$date,$type,$narration,$reference,$status,$totalDr,$totalCr,$userId);
            $stmt->execute();
            $jId=$mysqli->insert_id;
            $stmt->close();

            $lStmt=$mysqli->prepare(
                "INSERT INTO journal_entry_lines (journal_id,account_head,sub_account_head,account_code,debit_amount,credit_amount,cost_center,line_narration,sort_order)
                 VALUES (?,?,?,?,?,?,?,?,?)"
            );
            foreach ($cleanLines as $l) {
                $lStmt->bind_param('isssddssi',$jId,$l['account_head'],$l['sub_account_head'],$l['account_code'],$l['debit_amount'],$l['credit_amount'],$l['cost_center'],$l['line_narration'],$l['sort_order']);
                $lStmt->execute();
            }
            $lStmt->close();

            // If posting directly, also create GL entries + transaction record
            if (!$asDraft) {
                $glStmt=$mysqli->prepare(
                    "INSERT INTO gl_entries (transaction_id,voucher_number,entry_date,account_name,account_code,debit_amount,credit_amount,narration,cost_center,created_by)
                     VALUES (0,?,?,?,?,?,?,?,?,?)"
                );
                // Insert transactions record first
                $txStmt=$mysqli->prepare(
                    "INSERT INTO transactions (voucher_number,transaction_date,transaction_type,account_head,amount,narration,document_reference,entered_by,approval_status,is_cancelled)
                     VALUES (?,'$date','Journal',?,?,?,?,?,'approved',0)"
                );
                $ah=$cleanLines[0]['account_head'];
                $txStmt->bind_param('ssdsssi',$voucher,$ah,$totalDr,$narration,$reference,$userId);
                $txStmt->execute();
                $txId=$mysqli->insert_id;
                $txStmt->close();

                foreach ($cleanLines as $l) {
                    $glStmt->bind_param('isssddssi',$txId,$voucher,$date,$l['account_head'],$l['account_code'],$l['debit_amount'],$l['credit_amount'],$l['line_narration']?:$narration,$l['cost_center'],$userId);
                    $glStmt->execute();
                }
                $glStmt->close();

                $mysqli->query("UPDATE journal_entries SET posted_by=$userId, posted_at=NOW() WHERE id=$jId");
            }

            $mysqli->commit();
            json_response(['success'=>true,'id'=>$jId,'voucher_number'=>$voucher,'status'=>$status,'message'=>$asDraft?'Saved as draft':'Journal posted successfully']);
        } catch (Exception $e) {
            $mysqli->rollback();
            json_response(['message'=>'DB error: '.$e->getMessage()],500);
        }
        break;

    case 'post':
        // Post a draft journal
        if (!has_role(['admin','super_admin','accountant','finance_manager']))
            json_response(['message'=>'Access denied'],403);
        if (!validate_csrf($_POST['csrf']??'')) json_response(['message'=>'Invalid CSRF'],400);
        $id=(int)($_POST['id']??0);
        if (!$id) json_response(['message'=>'ID required'],400);

        $j=$mysqli->query("SELECT * FROM journal_entries WHERE id=$id")->fetch_assoc();
        if (!$j) json_response(['message'=>'Not found'],404);
        if ($j['status']!=='Draft') json_response(['message'=>'Only drafts can be posted'],400);

        $lines=[];
        $r=$mysqli->query("SELECT * FROM journal_entry_lines WHERE journal_id=$id ORDER BY sort_order");
        while($row=$r->fetch_assoc()) $lines[]=$row;

        $totalDr=array_sum(array_column($lines,'debit_amount'));
        $totalCr=array_sum(array_column($lines,'credit_amount'));
        if (round($totalDr,2)!==round($totalCr,2))
            json_response(['message'=>'Cannot post: Debits ('.number_format($totalDr,2).') ≠ Credits ('.number_format($totalCr,2).')'],400);

        $userId=$_SESSION['user']['id']??null;
        $mysqli->begin_transaction();
        try {
            $txStmt=$mysqli->prepare(
                "INSERT INTO transactions (voucher_number,transaction_date,transaction_type,account_head,amount,narration,document_reference,entered_by,approval_status,is_cancelled)
                 VALUES (?,?,'Journal',?,?,?,?,?,'approved',0)"
            );
            $ah=$lines[0]['account_head'];
            $txStmt->bind_param('ssdsssi',$j['voucher_number'],$j['entry_date'],$ah,$totalDr,$j['narration'],$j['reference'],$userId);
            $txStmt->execute();
            $txId=$mysqli->insert_id;
            $txStmt->close();

            $glStmt=$mysqli->prepare(
                "INSERT INTO gl_entries (transaction_id,voucher_number,entry_date,account_name,account_code,debit_amount,credit_amount,narration,cost_center,created_by)
                 VALUES (?,?,?,?,?,?,?,?,?,?)"
            );
            foreach ($lines as $l) {
                $glStmt->bind_param('issssddssi',$txId,$j['voucher_number'],$j['entry_date'],$l['account_head'],$l['account_code'],$l['debit_amount'],$l['credit_amount'],$l['line_narration']?:$j['narration'],$l['cost_center'],$userId);
                $glStmt->execute();
            }
            $glStmt->close();

            $mysqli->query("UPDATE journal_entries SET status='Posted',posted_by=$userId,posted_at=NOW(),total_debit=$totalDr,total_credit=$totalCr WHERE id=$id");
            $mysqli->commit();
            json_response(['success'=>true,'message'=>'Journal posted','transaction_id'=>$txId]);
        } catch (Exception $e) {
            $mysqli->rollback();
            json_response(['message'=>$e->getMessage()],500);
        }
        break;

    case 'reverse':
        if (!has_role(['admin','super_admin'])) json_response(['message'=>'Access denied'],403);
        if (!validate_csrf($_POST['csrf']??'')) json_response(['message'=>'Invalid CSRF'],400);
        $id=(int)($_POST['id']??0);
        $rev_date=trim($_POST['reversal_date']??date('Y-m-d'));
        if (!$id) json_response(['message'=>'ID required'],400);

        $j=$mysqli->query("SELECT * FROM journal_entries WHERE id=$id")->fetch_assoc();
        if (!$j || $j['status']!=='Posted') json_response(['message'=>'Only posted journals can be reversed'],400);

        $lines=[];
        $r=$mysqli->query("SELECT * FROM journal_entry_lines WHERE journal_id=$id ORDER BY sort_order");
        while($row=$r->fetch_assoc()) $lines[]=$row;

        $userId=$_SESSION['user']['id']??null;
        $voucher=generateJournalVoucher($mysqli,$rev_date);
        $narration='Reversal of '.$j['voucher_number'].': '.$j['narration'];

        $mysqli->begin_transaction();
        try {
            $stmt=$mysqli->prepare(
                "INSERT INTO journal_entries (voucher_number,entry_date,entry_type,narration,reference,status,total_debit,total_credit,created_by,posted_by,posted_at,reversal_of)
                 VALUES (?,?,'Reversing',?,?,?,?,?,?,?,NOW(),?)"
            );
            $ref='REV-'.$j['voucher_number'];
            $status='Posted';
            $stmt->bind_param('ssssssddiiii',$voucher,$rev_date,$narration,$ref,$status,$j['total_credit'],$j['total_debit'],$userId,$userId,$id);
            $stmt->execute();
            $newId=$mysqli->insert_id;
            $stmt->close();

            $lStmt=$mysqli->prepare(
                "INSERT INTO journal_entry_lines (journal_id,account_head,account_code,debit_amount,credit_amount,cost_center,line_narration,sort_order)
                 VALUES (?,?,?,?,?,?,?,?)"
            );
            // Swap debit/credit for reversal
            $txStmt=$mysqli->prepare(
                "INSERT INTO transactions (voucher_number,transaction_date,transaction_type,account_head,amount,narration,document_reference,entered_by,approval_status,is_cancelled)
                 VALUES (?,?,'Journal',?,?,?,?,?,'approved',0)"
            );
            $ah=$lines[0]['account_head'];
            $txStmt->bind_param('ssdsssi',$voucher,$rev_date,$ah,$j['total_credit'],$narration,$ref,$userId);
            $txStmt->execute();
            $txId=$mysqli->insert_id;
            $txStmt->close();

            $glStmt=$mysqli->prepare(
                "INSERT INTO gl_entries (transaction_id,voucher_number,entry_date,account_name,account_code,debit_amount,credit_amount,narration,cost_center,created_by)
                 VALUES (?,?,?,?,?,?,?,?,?,?)"
            );
            foreach ($lines as $i=>$l) {
                // swap
                $lStmt->bind_param('issddssi',$newId,$l['account_head'],$l['account_code'],$l['credit_amount'],$l['debit_amount'],$l['cost_center'],$narration,$i);
                $lStmt->execute();
                $glStmt->bind_param('issssddssi',$txId,$voucher,$rev_date,$l['account_head'],$l['account_code'],$l['credit_amount'],$l['debit_amount'],$narration,$l['cost_center'],$userId);
                $glStmt->execute();
            }
            $lStmt->close(); $glStmt->close();

            $mysqli->query("UPDATE journal_entries SET status='Reversed',reversed_by=$userId,reversed_at=NOW() WHERE id=$id");
            $mysqli->commit();
            json_response(['success'=>true,'new_id'=>$newId,'voucher_number'=>$voucher,'message'=>'Reversal journal created and posted']);
        } catch (Exception $e) {
            $mysqli->rollback();
            json_response(['message'=>$e->getMessage()],500);
        }
        break;

    case 'delete':
        if (!has_role(['admin','super_admin'])) json_response(['message'=>'Access denied'],403);
        if (!validate_csrf($_POST['csrf']??'')) json_response(['message'=>'Invalid CSRF'],400);
        $id=(int)($_POST['id']??0);
        if (!$id) json_response(['message'=>'ID required'],400);
        $j=$mysqli->query("SELECT status FROM journal_entries WHERE id=$id")->fetch_assoc();
        if (!$j) json_response(['message'=>'Not found'],404);
        if ($j['status']==='Posted') json_response(['message'=>'Posted journals cannot be deleted. Reverse instead.'],400);
        $mysqli->query("DELETE FROM journal_entries WHERE id=$id"); // CASCADE deletes lines
        json_response(['success'=>true,'message'=>'Draft deleted']);
        break;

    default:
        json_response(['message'=>'Unknown action'],400);
}
