<?php

require_once 'Logger.php';

class Request {
    private $conn;
    private $logger;

    public function __construct($conn, $logger = null) {
        $this->conn = $conn;
        $this->logger = $logger;
    }

    public function createRequest($branchId, $createdBy, $requestNumber, $items, $notes = '') {
        try {
            if (empty($requestNumber) || empty($items) || !is_array($items)) {
                throw new Exception("Invalid input data: required fields are missing or invalid.");
            }
          

            $this->conn->beginTransaction();

            $sql = "INSERT INTO requests (request_number, branch_id, created_by, notes, created_at)
                    VALUES (:request_number, :branch_id, :created_by, :notes, NOW())";

            $stmt = $this->conn->prepare($sql);
            $stmt->bindParam(':request_number', $requestNumber);
            $stmt->bindParam(':branch_id', $branchId, PDO::PARAM_INT);
            $stmt->bindParam(':created_by', $createdBy, PDO::PARAM_INT);
          
            $stmt->bindParam(':notes', $notes);

            if (!$stmt->execute()) {
                throw new Exception("Failed to create request header: database error.");
            }

            $requestId = $this->conn->lastInsertId();

            $itemSql = "INSERT INTO request_items (request_id, item_id, unique_code, item_name, quantity)
                        VALUES (:request_id, NULL, NULL, :item_name, :quantity)";
            $itemStmt = $this->conn->prepare($itemSql);

            foreach ($items as $item) {
                if (!isset($item['qty']) || !isset($item['item_name'])) {
                    throw new Exception("Invalid item data: missing qty, item_name, or unit_price.");
                }
                if ($item['qty'] <= 0 || empty($item['item_name'])) {
                    throw new Exception("Invalid item data: qty and item_name must not be empty.");
                }

                $itemStmt->bindParam(':request_id', $requestId, PDO::PARAM_INT);
                $itemStmt->bindParam(':item_name', $item['item_name']);
                $itemStmt->bindParam(':quantity', $item['qty'], PDO::PARAM_INT);

                if (!$itemStmt->execute()) {
                    throw new Exception("Failed to add item {$item['item_name']} to request: database error.");
                }
            }

            $this->conn->commit();

            if ($this->logger) {
                $requestData = [
                    'request_number' => $requestNumber,
                    'branch_id' => $branchId,
                    'created_by' => $createdBy,
                    'notes' => $notes,
                    'items_count' => count($items)
                ];
                $this->logger->logRequest('CREATE', $requestId, $requestData);
            }

            return [
                'success' => true,
                'request_id' => $requestId,
                'message' => 'Request created successfully.'
            ];

        } catch (Exception $e) {
            if ($this->conn->inTransaction()) {
                $this->conn->rollBack();
            }
            error_log("Error creating request: " . $e->getMessage());
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    public function createFromStocktakingMissingItems($branchId, $createdBy, $requestNumber, $missingItems, $sessionId) {
        try {
            if (empty($requestNumber) || empty($missingItems) || !is_array($missingItems) || empty($sessionId)) {
                throw new Exception("Invalid input data: missing stocktaking request details.");
            }

            $marker = '[STOCKTAKING_SESSION:' . (int)$sessionId . ']';

            $existingSql = "SELECT request_id FROM requests
                            WHERE branch_id = :branch_id AND notes LIKE :marker
                            ORDER BY request_id DESC
                            LIMIT 1";
            $existingStmt = $this->conn->prepare($existingSql);
            $existingStmt->bindValue(':branch_id', $branchId, PDO::PARAM_INT);
            $existingStmt->bindValue(':marker', '%' . $marker . '%', PDO::PARAM_STR);
            $existingStmt->execute();
            $existingRequestId = $existingStmt->fetchColumn();

            if ($existingRequestId) {
                return [
                    'success' => true,
                    'request_id' => (int)$existingRequestId,
                    'already_exists' => true,
                    'message' => 'A request for this stocktaking report already exists.'
                ];
            }

            $notes = "Missing items generated from stocktaking session #{$sessionId}. {$marker}";

            $this->conn->beginTransaction();

            $sql = "INSERT INTO requests (request_number, branch_id, created_by, notes, created_at)
                    VALUES (:request_number, :branch_id, :created_by, :notes, NOW())";
            $stmt = $this->conn->prepare($sql);
            $stmt->bindValue(':request_number', $requestNumber, PDO::PARAM_STR);
            $stmt->bindValue(':branch_id', $branchId, PDO::PARAM_INT);
            $stmt->bindValue(':created_by', $createdBy, PDO::PARAM_INT);
            $stmt->bindValue(':notes', $notes, PDO::PARAM_STR);
            $stmt->execute();

            $requestId = $this->conn->lastInsertId();

            $itemSql = "INSERT INTO request_items (request_id, item_id, unique_code, item_name, quantity)
                        VALUES (:request_id, :item_id, :unique_code, :item_name, 1)";
            $itemStmt = $this->conn->prepare($itemSql);

            foreach ($missingItems as $item) {
                $itemName = trim($item['item_name'] ?? '');
                $uniqueCode = trim($item['unique_code'] ?? '');
                $itemId = isset($item['item_id']) && $item['item_id'] !== '' ? (int)$item['item_id'] : null;

                if ($itemName === '' && $uniqueCode === '') {
                    continue;
                }

                if ($itemName === '') {
                    $itemName = 'Unknown Item';
                }

                $itemStmt->bindValue(':request_id', $requestId, PDO::PARAM_INT);
                $itemStmt->bindValue(':item_id', $itemId, $itemId === null ? PDO::PARAM_NULL : PDO::PARAM_INT);
                $itemStmt->bindValue(':unique_code', $uniqueCode !== '' ? $uniqueCode : null, $uniqueCode !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL);
                $itemStmt->bindValue(':item_name', $itemName, PDO::PARAM_STR);
                $itemStmt->execute();
            }

            $this->conn->commit();

            if ($this->logger) {
                $this->logger->logRequest('CREATE_STOCKTAKING_MISSING', $requestId, [
                    'request_number' => $requestNumber,
                    'branch_id' => $branchId,
                    'created_by' => $createdBy,
                    'stocktaking_session_id' => $sessionId,
                    'items_count' => count($missingItems)
                ]);
            }

            return [
                'success' => true,
                'request_id' => (int)$requestId,
                'already_exists' => false,
                'message' => 'Missing items request created successfully.'
            ];
        } catch (Exception $e) {
            if ($this->conn->inTransaction()) {
                $this->conn->rollBack();
            }

            error_log("Error creating stocktaking missing items request: " . $e->getMessage());
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    public function getRequestById($requestId) {
        $query = "SELECT q.request_id, q.request_number, q.created_at,  q.status,  q.notes, q.branch_id, q.created_by
              FROM requests q
              WHERE q.request_id = :request_id";
        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(':request_id', $requestId, PDO::PARAM_INT);
        $stmt->execute();
        $request = $stmt->fetch(PDO::FETCH_ASSOC);

        if ($request) {
            $itemQuery = "SELECT item_name, quantity FROM request_items WHERE request_id = :request_id";
            $itemStmt = $this->conn->prepare($itemQuery);
            $itemStmt->bindParam(':request_id', $requestId, PDO::PARAM_INT);
            $itemStmt->execute();
            $request['items'] = $itemStmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
        } else {
            $request = [];
        }

        return $request;
    }

    public function updateRequest($requestId,  $status, $items, $notes) {
        $oldData = null;
        if ($this->logger) {
            $oldData = $this->getRequestById($requestId);
        }

        $this->conn->beginTransaction();

        try {
            $deleteItemsQuery = "DELETE FROM request_items WHERE request_id = :request_id";
            $deleteStmt = $this->conn->prepare($deleteItemsQuery);
            $deleteStmt->bindParam(':request_id', $requestId, PDO::PARAM_INT);
            $deleteStmt->execute();

            $updateQuery = "UPDATE requests
                            SET 
                                status = :status,
                                notes = :notes
                            WHERE request_id = :request_id";
            $updateStmt = $this->conn->prepare($updateQuery);
            $updateStmt->bindParam(':request_id', $requestId, PDO::PARAM_INT);
            $updateStmt->bindParam(':status', $status);
            $updateStmt->bindParam(':notes', $notes);
            $updateStmt->execute();

            $insertItemQuery = "INSERT INTO request_items (request_id, quantity, item_name)
                                VALUES (:request_id, :quantity, :item_name)";
            $insertStmt = $this->conn->prepare($insertItemQuery);
            foreach ($items as $item) {
                $insertStmt->bindParam(':request_id', $requestId, PDO::PARAM_INT);
                $insertStmt->bindParam(':quantity', $item['qty'], PDO::PARAM_INT);
                $insertStmt->bindParam(':item_name', $item['item_name']);
                $insertStmt->execute();
            }

            $this->conn->commit();

            if ($this->logger && $oldData) {
                $newData = [
                    'status' => $status,
                    'notes' => $notes,
                    'items_count' => count($items)
                ];
               // $this->logger->logRequest('UPDATE', $requestId, $newData, $oldData);
            }

            return true;
        } catch (PDOException $e) {
            $this->conn->rollBack();
            error_log("Update request failed: " . $e->getMessage());
            return false;
        }
    }

    public function getAllRequests() {
        $query = "SELECT q.request_id, q.request_number, q.created_at, q.status, q.branch_id
                FROM requests q";
        $stmt = $this->conn->prepare($query);
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    public function getRequestsByBranch($branchId, $startDate = null, $endDate = null) {
        try {
            $sql = "SELECT q.*, u.username as created_by_name
                    FROM requests q
                    JOIN users u ON q.created_by = u.user_id
                    WHERE q.branch_id = :branch_id";

            if ($startDate && $endDate) {
                $sql .= " AND DATE(q.created_at) BETWEEN :start_date AND :end_date";
            }

            $sql .= " ORDER BY q.created_at DESC";

            $stmt = $this->conn->prepare($sql);
            $stmt->bindParam(':branch_id', $branchId, PDO::PARAM_INT);

            if ($startDate && $endDate) {
                $stmt->bindParam(':start_date', $startDate);
                $stmt->bindParam(':end_date', $endDate);
            }

            $stmt->execute();
            return $stmt->fetchAll(PDO::FETCH_ASSOC);

        } catch (Exception $e) {
            error_log("Error getting requests by branch: " . $e->getMessage());
            return [];
        }
    }

    public function convertToSale($requestId, $userId) {
        try {
            $request = $this->getRequestById($requestId);

            if (!$request) {
                throw new Exception("Request not found");
            }

            $this->conn->beginTransaction();

            $transactionId = 'SALE-' . date('Ymd') . '-' . mt_rand(1000, 9999);

            require_once __DIR__ . '/Sales.php';
            $sales = new Sales($this->conn, $this->logger);

            foreach ($request['items'] as $item) {
                $result = $sales->createSale(
                    date('Y-m-d H:i:s'),
                    $item['unique_code'] ?? null,
                    $item['unit_price'],
                    $item['quantity'],
                    $request['branch_id'],
                    $userId,
                    $transactionId
                );

                if (!$result) {
                    throw new Exception("Failed to create sale for item {$item['item_name']}");
                }
            }

            $updateSql = "UPDATE requests SET status = 'converted', converted_at = NOW(),
                          converted_by = :user_id, transaction_id = :transaction_id
                          WHERE request_id = :request_id";
            $updateStmt = $this->conn->prepare($updateSql);
            $updateStmt->bindParam(':user_id', $userId, PDO::PARAM_INT);
            $updateStmt->bindParam(':transaction_id', $transactionId);
            $updateStmt->bindParam(':request_id', $requestId, PDO::PARAM_INT);

            if (!$updateStmt->execute()) {
                throw new Exception("Failed to update request status");
            }

            $this->conn->commit();

            if ($this->logger) {
                $conversionData = [
                    'request_id' => $requestId,
                    'request_number' => $request['request_number'],
                    'transaction_id' => $transactionId,
                    'converted_by' => $userId,
                    'items_count' => count($request['items'])
                ];
                $this->logger->logRequest('CONVERT_TO_SALE', $requestId, $conversionData);
            }

            return $transactionId;

        } catch (Exception $e) {
            if ($this->conn->inTransaction()) {
                $this->conn->rollBack();
            }
            error_log("Error converting request to sale: " . $e->getMessage());
            return false;
        }
    }

    public function deleteRequest($requestId) {
        try {
            $requestData = null;
            if ($this->logger) {
                $requestData = $this->getRequestById($requestId);
            }

            $this->conn->beginTransaction();
            $queryItems = "DELETE FROM request_items WHERE request_id = :request_id";
            $stmtItems = $this->conn->prepare($queryItems);
            $stmtItems->bindParam(':request_id', $requestId, PDO::PARAM_INT);
            $stmtItems->execute();

            $query = "DELETE FROM requests WHERE request_id = :request_id";
            $stmt = $this->conn->prepare($query);
            $stmt->bindParam(':request_id', $requestId, PDO::PARAM_INT);
            $success = $stmt->execute();

            if ($success && $this->logger && $requestData) {
                $this->logger->logRequest('DELETE', $requestId, null, $requestData);
            }

            $this->conn->commit();
            return $success;
        } catch (PDOException $e) {
            $this->conn->rollBack();
            error_log("Error deleting request: " . $e->getMessage());
            throw new Exception("Database error: " . $e->getMessage());
        }
    }
}
?>
