<?php
declare(strict_types=1);

header('Content-Type: text/plain; charset=utf-8');
ini_set('display_errors', '1');
error_reporting(E_ALL);

if (session_status() !== PHP_SESSION_ACTIVE) {
    session_start();
}

require_once __DIR__ . '/../includes/db.php';

$mysqli = $conn ?? ($mysqli ?? null);
if (!$mysqli instanceof mysqli) {
    http_response_code(500);
    exit('DB connection missing');
}
$mysqli->set_charset('utf8mb4');

/* -------------------------------------------------------
 * helpers
 * -----------------------------------------------------*/
function tableExists(mysqli $db, string $table): bool {
    $st = $db->prepare("
        SELECT 1
        FROM INFORMATION_SCHEMA.TABLES
        WHERE TABLE_SCHEMA = DATABASE()
          AND TABLE_NAME = ?
        LIMIT 1
    ");
    if (!$st) return false;
    $st->bind_param('s', $table);
    $st->execute();
    $st->store_result();
    $ok = $st->num_rows > 0;
    $st->free_result();
    $st->close();
    return $ok;
}

function colExists(mysqli $db, string $table, string $column): bool {
    $st = $db->prepare("
        SELECT 1
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_SCHEMA = DATABASE()
          AND TABLE_NAME = ?
          AND COLUMN_NAME = ?
        LIMIT 1
    ");
    if (!$st) return false;
    $st->bind_param('ss', $table, $column);
    $st->execute();
    $st->store_result();
    $ok = $st->num_rows > 0;
    $st->free_result();
    $st->close();
    return $ok;
}

function num($v): float {
    $s = preg_replace('/[^0-9.\-]/', '', (string)$v);
    if ($s === '' || $s === '-' || $s === '.' || $s === '-.') return 0.0;
    $f = (float)$s;
    return is_finite($f) ? $f : 0.0;
}

function fetchOneAssoc(mysqli_stmt $st): ?array {
    $res = method_exists($st, 'get_result') ? $st->get_result() : null;
    if (!$res) return null;
    $row = $res->fetch_assoc();
    return $row ?: null;
}

function resolveStudentExists(mysqli $db, int $studentId): bool {
    if (!tableExists($db, 'studentss')) return false;
    $st = $db->prepare("SELECT id FROM studentss WHERE id = ? LIMIT 1");
    if (!$st) return false;
    $st->bind_param('i', $studentId);
    $st->execute();
    $row = fetchOneAssoc($st);
    $st->close();
    return !empty($row);
}

function resolveLatestStudentPlan(mysqli $db, int $studentId, int $courseId = 0): ?array {
    if (!tableExists($db, 'student_fee_plans')) return null;
    if (!colExists($db, 'student_fee_plans', 'student_id')) return null;

    $hasCourseId = colExists($db, 'student_fee_plans', 'course_id');

    if ($courseId > 0 && $hasCourseId) {
        $st = $db->prepare("
            SELECT *
            FROM student_fee_plans
            WHERE student_id = ?
              AND course_id = ?
            ORDER BY id DESC
            LIMIT 1
        ");
        if (!$st) return null;
        $st->bind_param('ii', $studentId, $courseId);
    } else {
        $st = $db->prepare("
            SELECT *
            FROM student_fee_plans
            WHERE student_id = ?
            ORDER BY id DESC
            LIMIT 1
        ");
        if (!$st) return null;
        $st->bind_param('i', $studentId);
    }

    $st->execute();
    $row = fetchOneAssoc($st);
    $st->close();

    return $row ?: null;
}

function resolvePlanById(mysqli $db, int $planId, int $studentId, int $courseId = 0): ?array {
    if ($planId <= 0) return null;
    if (!tableExists($db, 'student_fee_plans')) return null;

    $hasStudentId = colExists($db, 'student_fee_plans', 'student_id');
    $hasCourseId  = colExists($db, 'student_fee_plans', 'course_id');

    $sql = "SELECT * FROM student_fee_plans WHERE id = ?";
    $types = 'i';
    $params = [$planId];

    if ($hasStudentId) {
        $sql .= " AND student_id = ?";
        $types .= 'i';
        $params[] = $studentId;
    }
    if ($courseId > 0 && $hasCourseId) {
        $sql .= " AND course_id = ?";
        $types .= 'i';
        $params[] = $courseId;
    }

    $sql .= " LIMIT 1";

    $st = $db->prepare($sql);
    if (!$st) return null;
    $st->bind_param($types, ...$params);
    $st->execute();
    $row = fetchOneAssoc($st);
    $st->close();

    return $row ?: null;
}

function resolveCourseId(mysqli $db, int $studentId, int $postedCourseId, int $postedPlanId): int {
    if ($postedCourseId > 0) return $postedCourseId;

    if ($postedPlanId > 0 && tableExists($db, 'student_fee_plans') && colExists($db, 'student_fee_plans', 'course_id')) {
        $st = $db->prepare("SELECT course_id FROM student_fee_plans WHERE id = ? LIMIT 1");
        if ($st) {
            $st->bind_param('i', $postedPlanId);
            $st->execute();
            $row = fetchOneAssoc($st);
            $st->close();
            $cid = (int)($row['course_id'] ?? 0);
            if ($cid > 0) return $cid;
        }
    }

    $planRow = resolveLatestStudentPlan($db, $studentId);
    if ($planRow) {
        $cid = (int)($planRow['course_id'] ?? 0);
        if ($cid > 0) return $cid;
    }

    if (tableExists($db, 'studentss') && colExists($db, 'studentss', 'course_id')) {
        $st = $db->prepare("SELECT course_id FROM studentss WHERE id = ? LIMIT 1");
        if ($st) {
            $st->bind_param('i', $studentId);
            $st->execute();
            $row = fetchOneAssoc($st);
            $st->close();
            $cid = (int)($row['course_id'] ?? 0);
            if ($cid > 0) return $cid;
        }
    }

    return 0;
}

function resolveCurrentPlan(mysqli $db, int $studentId, int $courseId, int $postedPlanId = 0): ?array {
    if ($postedPlanId > 0) {
        $plan = resolvePlanById($db, $postedPlanId, $studentId, $courseId);
        if ($plan) return $plan;
    }

    $plan = resolveLatestStudentPlan($db, $studentId, $courseId);
    if ($plan) return $plan;

    return null;
}

function resolvePlanType(array $planRow): string {
    $planType = strtolower(trim((string)($planRow['plan_type'] ?? '')));
    if ($planType !== '') return $planType;

    $planName = strtolower(trim((string)($planRow['plan_name'] ?? '')));
    if (strpos($planName, 'install') !== false) return 'installment';
    if (strpos($planName, 'one-time') !== false || strpos($planName, 'one time') !== false) return 'one';

    return '';
}

function resolveUnpaidScheduleId(mysqli $db, int $studentId, int $planId): ?int {
    if ($studentId <= 0 || $planId <= 0) return null;
    if (!tableExists($db, 'payment_schedule')) return null;

    $hasPlanId    = colExists($db, 'payment_schedule', 'plan_id');
    $hasStudentId = colExists($db, 'payment_schedule', 'student_id');
    if (!$hasStudentId) return null;

    $sql = "
        SELECT
            ps.id,
            ps.installment_no,
            ps.due_date,
            (COALESCE(ps.course_fee_lkr,0) + COALESCE(ps.registration_fee_lkr,0)) AS due_amount,
            COALESCE((
                SELECT SUM(COALESCE(p.amount,0))
                FROM payments p
                WHERE p.schedule_id = ps.id
            ),0) AS paid_amount
        FROM payment_schedule ps
        WHERE ps.student_id = ?
    ";

    $types = 'i';
    $params = [$studentId];

    if ($hasPlanId) {
        $sql .= " AND ps.plan_id = ?";
        $types .= 'i';
        $params[] = $planId;
    }

    $sql .= " ORDER BY ps.due_date ASC, ps.id ASC";

    $st = $db->prepare($sql);
    if (!$st) return null;
    $st->bind_param($types, ...$params);
    $st->execute();
    $res = $st->get_result();

    $firstId = null;
    $picked  = null;

    while ($row = $res->fetch_assoc()) {
        $id   = (int)($row['id'] ?? 0);
        $due  = (float)($row['due_amount'] ?? 0);
        $paid = (float)($row['paid_amount'] ?? 0);

        if ($firstId === null && $id > 0) {
            $firstId = $id;
        }

        if ($due > $paid + 0.009) {
            $picked = $id;
            break;
        }
    }

    $st->close();

    if ($picked !== null && $picked > 0) return $picked;
    if ($firstId !== null && $firstId > 0) return $firstId;

    return null;
}

function resolveBranchCashier(mysqli $db): array {
    $branchName = trim((string)(
        $_SESSION['branch_name'] ??
        ($_SESSION['user']['branch_name'] ?? '') ??
        ($_SESSION['user']['branch'] ?? '') ??
        ($_SESSION['branch'] ?? '')
    ));

    $cashierName = trim((string)(
        $_SESSION['display_name'] ??
        ($_SESSION['user']['display_name'] ?? '') ??
        $_SESSION['name'] ??
        ($_SESSION['user']['name'] ?? '') ??
        $_SESSION['full_name'] ??
        ($_SESSION['user']['full_name'] ?? '') ??
        ''
    ));

    // try session user id
    $sessionUserId = (int)(
        $_SESSION['user_id'] ??
        ($_SESSION['user']['id'] ?? 0) ??
        0
    );

    // fallback: load from users table by id
    if (($cashierName === '' || $branchName === '') && $sessionUserId > 0 && tableExists($db, 'users')) {
        $sql = "SELECT name, branch_name FROM users WHERE id = ? LIMIT 1";
        $st = $db->prepare($sql);
        if ($st) {
            $st->bind_param('i', $sessionUserId);
            $st->execute();
            $row = fetchOneAssoc($st);
            $st->close();

            if ($row) {
                if ($cashierName === '') {
                    $cashierName = trim((string)($row['name'] ?? ''));
                }
                if ($branchName === '') {
                    $branchName = trim((string)($row['branch_name'] ?? ''));
                }
            }
        }
    }

    // fallback: load from users table by email
    $sessionEmail = trim((string)(
        $_SESSION['email'] ??
        ($_SESSION['user']['email'] ?? '') ??
        ''
    ));

    if (($cashierName === '' || $branchName === '') && $sessionEmail !== '' && tableExists($db, 'users')) {
        $sql = "SELECT name, branch_name FROM users WHERE email = ? LIMIT 1";
        $st = $db->prepare($sql);
        if ($st) {
            $st->bind_param('s', $sessionEmail);
            $st->execute();
            $row = fetchOneAssoc($st);
            $st->close();

            if ($row) {
                if ($cashierName === '') {
                    $cashierName = trim((string)($row['name'] ?? ''));
                }
                if ($branchName === '') {
                    $branchName = trim((string)($row['branch_name'] ?? ''));
                }
            }
        }
    }

    if ($cashierName === '') $cashierName = 'Unknown';
    if ($branchName === '')  $branchName  = 'Main';

    return [$branchName, $cashierName];
}

/* -------------------------------------------------------
 * input
 * -----------------------------------------------------*/
$student_id       = (int)($_POST['student_id'] ?? 0);
$posted_plan_id   = (int)($_POST['plan_id'] ?? 0);
$posted_course_id = (int)($_POST['course_id'] ?? 0);

$amount_lkr       = num($_POST['amount'] ?? 0);
$usd_amount       = num($_POST['usd_amount'] ?? 0);
$currency         = strtoupper(trim((string)($_POST['currency'] ?? 'LKR')));
$payment_method   = trim((string)($_POST['payment_method'] ?? 'Cash'));
$reference_no     = trim((string)($_POST['reference_no'] ?? ''));
$notes            = trim((string)($_POST['notes'] ?? ''));
$items_json       = trim((string)($_POST['items_json'] ?? ''));
$fee_type         = trim((string)($_POST['fee_type'] ?? 'Mixed'));

if ($student_id <= 0) {
    http_response_code(400);
    exit('Invalid student_id');
}
if (!resolveStudentExists($mysqli, $student_id)) {
    http_response_code(404);
    exit('Student not found');
}
if ($amount_lkr < 0 || $usd_amount < 0) {
    http_response_code(400);
    exit('Invalid payment amount');
}
if ($amount_lkr <= 0 && $usd_amount <= 0) {
    http_response_code(400);
    exit('Amount cannot be 0');
}
if ($payment_method === '') {
    $payment_method = 'Cash';
}
if ($currency === '') {
    $currency = 'LKR';
}
if ($items_json !== '') {
    $decoded = json_decode($items_json, true);
    if (!is_array($decoded)) {
        http_response_code(400);
        exit('Invalid items_json');
    }
}

/* -------------------------------------------------------
 * resolve course / plan / schedule
 * -----------------------------------------------------*/
$course_id_final = resolveCourseId($mysqli, $student_id, $posted_course_id, $posted_plan_id);
if ($course_id_final <= 0) {
    http_response_code(422);
    exit('Unable to resolve course_id');
}

$planRow = resolveCurrentPlan($mysqli, $student_id, $course_id_final, $posted_plan_id);
if (!$planRow) {
    http_response_code(422);
    exit('Unable to resolve current fee plan');
}

$plan_id_final = (int)($planRow['id'] ?? 0);
if ($plan_id_final <= 0) {
    http_response_code(422);
    exit('Invalid plan_id');
}

$plan_type = resolvePlanType($planRow);
$is_installment = in_array($plan_type, ['installment', 'inst'], true);

$schedule_id = null;
if ($is_installment) {
    $schedule_id = resolveUnpaidScheduleId($mysqli, $student_id, $plan_id_final);
    if (!$schedule_id) {
        http_response_code(422);
        exit('Unable to resolve unpaid/current schedule_id for installment plan');
    }
}

/* -------------------------------------------------------
 * branch / cashier
 * -----------------------------------------------------*/
[$branch_name, $cashier_name] = resolveBranchCashier($mysqli);

/* -------------------------------------------------------
 * payments table columns
 * -----------------------------------------------------*/
if (!tableExists($mysqli, 'payments')) {
    http_response_code(500);
    exit('payments table not found');
}

$col_student = colExists($mysqli, 'payments', 'student_id') ? 'student_id' : null;
$col_amount  = colExists($mysqli, 'payments', 'amount') ? 'amount' : null;
$col_course  = colExists($mysqli, 'payments', 'course_id') ? 'course_id' : null;
$col_plan    = colExists($mysqli, 'payments', 'plan_id') ? 'plan_id' : null;
$col_sched   = colExists($mysqli, 'payments', 'schedule_id') ? 'schedule_id' : null;
$col_method  = colExists($mysqli, 'payments', 'payment_method') ? 'payment_method'
            : (colExists($mysqli, 'payments', 'method') ? 'method' : null);
$col_ref     = colExists($mysqli, 'payments', 'reference_no') ? 'reference_no'
            : (colExists($mysqli, 'payments', 'ref_no') ? 'ref_no' : null);
$col_notes   = colExists($mysqli, 'payments', 'notes') ? 'notes' : null;
$col_date    = colExists($mysqli, 'payments', 'date_paid') ? 'date_paid'
            : (colExists($mysqli, 'payments', 'created_at') ? 'created_at' : null);
$col_usd     = colExists($mysqli, 'payments', 'usd_amount') ? 'usd_amount' : null;
$col_curr    = colExists($mysqli, 'payments', 'currency') ? 'currency' : null;
$col_fee     = colExists($mysqli, 'payments', 'fee_type') ? 'fee_type' : null;
$col_items   = colExists($mysqli, 'payments', 'items_json') ? 'items_json' : null;
$col_branch  = colExists($mysqli, 'payments', 'branch_name') ? 'branch_name' : null;
$col_cashier = colExists($mysqli, 'payments', 'cashier_name') ? 'cashier_name' : null;

if (!$col_student || !$col_amount) {
    http_response_code(500);
    exit('payments table missing required columns');
}
if ($col_course && $course_id_final <= 0) {
    http_response_code(422);
    exit('course_id missing');
}
if ($col_plan && $plan_id_final <= 0) {
    http_response_code(422);
    exit('plan_id missing');
}
if ($is_installment && $col_sched && (int)$schedule_id <= 0) {
    http_response_code(422);
    exit('schedule_id missing for installment plan');
}

/* -------------------------------------------------------
 * save
 * -----------------------------------------------------*/
$mysqli->begin_transaction();

try {
    $cols = [];
    $vals = [];
    $types = '';
    $binds = [];

    $cols[] = $col_student;
    $vals[] = '?';
    $types .= 'i';
    $binds[] = $student_id;

    $cols[] = $col_amount;
    $vals[] = '?';
    $types .= 'd';
    $binds[] = $amount_lkr;

    if ($col_course) {
        $cols[] = $col_course;
        $vals[] = '?';
        $types .= 'i';
        $binds[] = $course_id_final;
    }

    if ($col_plan) {
        $cols[] = $col_plan;
        $vals[] = '?';
        $types .= 'i';
        $binds[] = $plan_id_final;
    }

    if ($col_sched) {
        $cols[] = $col_sched;
        $vals[] = '?';
        $types .= 'i';
        $binds[] = (int)($schedule_id ?? 0);
    }

    if ($col_method) {
        $cols[] = $col_method;
        $vals[] = '?';
        $types .= 's';
        $binds[] = $payment_method;
    }

    if ($col_ref) {
        $cols[] = $col_ref;
        $vals[] = '?';
        $types .= 's';
        $binds[] = $reference_no;
    }

    if ($col_notes) {
        $cols[] = $col_notes;
        $vals[] = '?';
        $types .= 's';
        $binds[] = $notes;
    }

    if ($col_date) {
        $cols[] = $col_date;
        $vals[] = 'NOW()';
    }

    if ($col_usd) {
        $cols[] = $col_usd;
        $vals[] = '?';
        $types .= 'd';
        $binds[] = $usd_amount;
    }

    if ($col_curr) {
        $cols[] = $col_curr;
        $vals[] = '?';
        $types .= 's';
        $binds[] = $currency;
    }

    if ($col_fee) {
        $cols[] = $col_fee;
        $vals[] = '?';
        $types .= 's';
        $binds[] = $fee_type;
    }

    if ($col_items) {
        $cols[] = $col_items;
        $vals[] = '?';
        $types .= 's';
        $binds[] = $items_json;
    }

    if ($col_branch) {
        $cols[] = $col_branch;
        $vals[] = '?';
        $types .= 's';
        $binds[] = $branch_name;
    }

    if ($col_cashier) {
        $cols[] = $col_cashier;
        $vals[] = '?';
        $types .= 's';
        $binds[] = $cashier_name;
    }

    $sql = "INSERT INTO payments (`" . implode('`,`', $cols) . "`) VALUES (" . implode(',', $vals) . ")";
    $st = $mysqli->prepare($sql);
    if (!$st) {
        throw new Exception('Prepare failed: ' . $mysqli->error);
    }

    if ($types !== '') {
        $st->bind_param($types, ...$binds);
    }

    if (!$st->execute()) {
        throw new Exception('Execute failed: ' . $st->error);
    }
    $st->close();

    $mysqli->commit();
    echo 'Payment saved successfully';
} catch (Throwable $e) {
    $mysqli->rollback();
    http_response_code(500);
    exit('Save failed: ' . $e->getMessage());
}