<?php
session_start();
require_once __DIR__ . '/../../includes/auth.php';
require_once __DIR__ . '/../../classes/Database.php';
require_once __DIR__ . '/../../classes/DiscountPolicy.php';
require_once __DIR__ . '/../../classes/Order.php';
require_once __DIR__ . '/../../classes/Request.php';
require_once __DIR__ . '/../../classes/Quotation.php';
require_once __DIR__ . '/../../classes/Sales.php';
require_once __DIR__ . '/../../classes/MraEisCompliance.php';
require_once __DIR__ . '/../../classes/SystemSettings.php';
require_once __DIR__ . '/../../classes/Logger.php';
require_once __DIR__ . '/../../classes/CustomerService.php';
require_once __DIR__ . '/../../classes/CreditSales.php';
require_once __DIR__ . '/../../includes/payment_options.php';

$database = new Database();
$conn = $database->getConnection();
$auth = new Auth($conn);
$auth->requireLogin();

$currentUserId = (int)$_SESSION['user_id'];
$requestedAction = $_POST['action'] ?? '';
$isControllerOrAdmin = $auth->isController($currentUserId) || $auth->isSuperAdmin($currentUserId);

// Carve-out: a branch user (not a controller/superadmin) may still reach this
// endpoint, but only to assign a code on their own branch's order, and only
// once that order is fully paid. Every other action stays controller/admin-only.
$branchCodeAssignmentAllowed = false;
$orderObj = new Order($conn);
if (!$isControllerOrAdmin && $requestedAction === 'complete_order_code' && $_SERVER['REQUEST_METHOD'] === 'POST') {
    $orderForCheck = $orderObj->getOrderById((int)($_POST['order_id'] ?? 0));
    if ($orderForCheck) {
        $userBranchId = $auth->getUserBranch($currentUserId);
        $balanceForCheck = $orderObj->getBalance((int)$orderForCheck['order_id'], $orderForCheck);
        $branchCodeAssignmentAllowed = ((int)$orderForCheck['branch_id'] === (int)$userBranchId) && $balanceForCheck <= 0.009;
    }
}

if (!$isControllerOrAdmin && !$branchCodeAssignmentAllowed) {
    header('Location: /IMS/unauthorized.php');
    exit();
}

function redirectController($message, $isError = false) {
    $key = $isError ? 'error' : 'success';
    header('Location: controller.php?' . $key . '=' . urlencode($message));
    exit();
}

function redirectOrderDetails($orderId, $message, $isError = false) {
    $key = $isError ? 'error' : 'success';
    header('Location: /IMS/views/orders/order_details.php?order_id=' . (int)$orderId . '&' . $key . '=' . urlencode($message));
    exit();
}

try {
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        redirectController('Invalid request.', true);
    }

    $action = $_POST['action'] ?? '';
    $userId = (int)$_SESSION['user_id'];

    if ($action === 'review_discount') {
        $policy = new DiscountPolicy($conn);
        $policy->reviewRequest((int)$_POST['request_id'], $_POST['status'] ?? '', $userId, $_POST['review_notes'] ?? '', !empty($_POST['create_rule']));
        redirectController('Discount request reviewed.');
    }

    if ($action === 'create_discount_rule') {
        $policy = new DiscountPolicy($conn);
        $policy->createRule($_POST['rule_name'] ?? '', $_POST['discount_type'] ?? 'percentage', $_POST['discount_value'] ?? 0, $_POST['max_sale_amount'] ?? null, $userId);
        redirectController('Discount rule created.');
    }

    if ($action === 'order_status') {
        $order = new Order($conn);
        $order->updateStatus((int)$_POST['order_id'], $_POST['status'] ?? 'pending');
        redirectController('Order status updated.');
    }

    if ($action === 'credit_status') {
        $status = $_POST['status'] ?? '';
        $creditSales = new CreditSales($conn);
        if (!$creditSales->approveCredit((int)$_POST['credit_id'], $status, $userId, $_POST['approval_notes'] ?? '')) {
            redirectController('Credit sale was not updated. It may already have been reviewed.', true);
        }
        redirectController('Credit sale ' . $status . '.');
    }

    if ($action === 'request_status') {
        $status = $_POST['status'] ?? '';
        if (!in_array($status, ['approved', 'rejected'], true)) {
            redirectController('Invalid request status.', true);
        }
        $conn->exec("ALTER TABLE requests MODIFY status ENUM('pending','converted','approved','rejected','expired') DEFAULT 'pending'");
        $stmt = $conn->prepare('UPDATE requests SET status = :status WHERE request_id = :id');
        $stmt->execute([':status' => $status, ':id' => (int)$_POST['id']]);
        redirectController('Branch request updated.');
    }

    if ($action === 'quotation_status') {
        $status = $_POST['status'] ?? '';
        if (!in_array($status, ['approved', 'rejected'], true)) {
            redirectController('Invalid quotation status.', true);
        }
        $conn->exec("ALTER TABLE quotations MODIFY status ENUM('pending','converted','approved','rejected','expired') DEFAULT 'pending'");
        $stmt = $conn->prepare('UPDATE quotations SET status = :status WHERE quotation_id = :id');
        $stmt->execute([':status' => $status, ':id' => (int)$_POST['id']]);
        redirectController('Quotation updated.');
    }

    if ($action === 'claim_followup') {
        $requestId = (int)($_POST['request_id'] ?? 0);
        $status = $_POST['status'] ?? 'open';
        $resolution = trim((string)($_POST['resolution'] ?? ''));
        $note = trim((string)($_POST['note'] ?? ''));
        $visibility = $_POST['visibility'] ?? 'internal';
        $allowedStatuses = ['open', 'in_progress', 'waiting_customer', 'approved', 'rejected', 'resolved', 'closed'];
        if ($requestId <= 0 || !in_array($status, $allowedStatuses, true)) {
            redirectController('Invalid claim follow-up details.', true);
        }

        $logger = new Logger($conn, $_SESSION['user_id'], $_SESSION['username'] ?? '', $_SESSION['role'] ?? '');
        $service = new CustomerService($conn, $logger);
        $claim = $service->getById($requestId);
        if (!$claim || ($claim['request_type'] ?? '') !== 'claim') {
            redirectController('Claim not found.', true);
        }

        if (!$service->updateRequest($requestId, $status, $resolution, $note, $visibility, $userId)) {
            redirectController('Claim follow-up was not saved.', true);
        }

        redirectController('Claim follow-up updated.');
    }

    if ($action === 'complete_order_code') {
        $order = $orderObj;
        $orderData = $order->getOrderById((int)$_POST['order_id']);
        if (!$orderData) {
            redirectOrderDetails((int)($_POST['order_id'] ?? 0), 'Order not found.', true);
        }
        if (!empty($orderData['assigned_code'])) {
            redirectOrderDetails((int)$orderData['order_id'], 'This order is already completed.', true);
        }
        $uniqueCodesRaw = is_array($_POST['unique_code'] ?? null) ? $_POST['unique_code'] : [$_POST['unique_code'] ?? ''];
        $codeValuesRaw = is_array($_POST['code_value'] ?? null) ? $_POST['code_value'] : [$_POST['code_value'] ?? $orderData['price']];
        $assignedItems = [];
        foreach ($uniqueCodesRaw as $index => $rawCode) {
            $code = trim((string)$rawCode);
            $value = round((float)($codeValuesRaw[$index] ?? 0), 2);
            if ($code !== '') {
                if (isset($assignedItems[$code])) {
                    redirectOrderDetails((int)$orderData['order_id'], 'Each assigned code must be unique.', true);
                }
                $assignedItems[$code] = $value;
            }
        }
        $finalPayment  = (float)($_POST['final_payment_amount'] ?? 0);
        $paymentMethod = normalizePaymentMethodValue($_POST['payment_method'] ?? 'cash');
        $saleAmount = round((float)$orderData['price'], 2);
        // Branch users may only assign a code on an already fully-paid order (enforced
        // above via $branchCodeAssignmentAllowed) — never let them record a payment here.
        if (!$isControllerOrAdmin) {
            $finalPayment = 0;
        }
        if (!$assignedItems) {
            redirectOrderDetails((int)$orderData['order_id'], 'At least one unique item code is required to complete the order.', true);
        }
        foreach ($assignedItems as $code => $value) {
            if ($value <= 0) {
                redirectOrderDetails((int)$orderData['order_id'], 'Every assigned code requires a positive value.', true);
            }
        }
        if (abs(array_sum($assignedItems) - $saleAmount) > 0.009) {
            redirectOrderDetails((int)$orderData['order_id'], 'Assigned code values must equal the order total of MWK ' . number_format($saleAmount, 2) . '.', true);
        }
        if ($finalPayment < 0) {
            redirectOrderDetails((int)$orderData['order_id'], 'Final payment amount cannot be negative.', true);
        }

        $logger = new Logger($conn, $_SESSION['user_id'], $_SESSION['username'], $_SESSION['role']);
        $sales  = new Sales($conn, $logger);
        $settings = new SystemSettings($conn);
        $imsOnly = $settings->imsOnly();
        $eis = $imsOnly ? null : new MraEisCompliance($conn);

        $transactionId = $imsOnly
            ? $sales->generateLocalTransactionNumber()
            : $sales->generateMraEisInvoiceNumber((int)$orderData['branch_id'], date('Y-m-d H:i:s'));

        $conn->beginTransaction();
        foreach ($assignedItems as $uniqueCode => $itemValue) {
            $sales->createSale(
                date('Y-m-d H:i:s'),
                $uniqueCode,
                $itemValue,
                (int)$orderData['branch_id'],
                $userId,
                $transactionId,
                $itemValue,
                $orderData['customer_name'] ?? null,
                $orderData['customer_contact'] ?? null,
                false,
                null,
                'B2C',
                null,
                null,
                false,
                $paymentMethod
            );
        }
        $outbox = null;
        if (!$imsOnly) {
            $outbox = $eis->prepareSale($transactionId, (int)$orderData['branch_id'], $userId, [
                'source'   => 'controller_order_non_income',
                'order_id' => (int)$orderData['order_id'],
            ]);
        }

        // completeWithCode now also records finalPayment in order_payments if > 0
        $order->completeWithCode(
            (int)$orderData['order_id'],
            implode(', ', array_keys($assignedItems)),
            $finalPayment,
            $paymentMethod,
            $userId,
            $imsOnly ? null : $transactionId,
            $outbox['outbox_id'] ?? null
        );
        $conn->commit();

        // Redirect to order receipt instead of controller dashboard
        header('Location: /IMS/views/orders/order_receipt.php?order_id=' . (int)$orderData['order_id'] . '&success=1');
        exit();
    }

    redirectController('Unknown controller action.', true);
} catch (Throwable $e) {
    if ($conn->inTransaction()) {
        $conn->rollBack();
    }
    error_log('Controller action failed: ' . $e->getMessage());
    if (($_POST['action'] ?? '') === 'complete_order_code') {
        redirectOrderDetails((int)($_POST['order_id'] ?? 0), $e->getMessage(), true);
    }
    redirectController($e->getMessage(), true);
}
?>
