<?php
/**
 * CartController.php
 *
 * Controller per gestione carrello fatturazione DFM
 * Endpoint per aggiungere/rimuovere/listare items nel carrello paziente
 *
 * @package DFM
 * @since 2026-01-16
 */

class CartController extends Zend_Controller_Action
{
    private $db;

    public function init()
    {
        $this->_helper->viewRenderer->setNoRender(true);
        header("Content-type: application/json");
        $this->checkAuth();
        $this->db = $this->getDb();
    }

    private function checkAuth() {
        $auth = Zend_Auth::getInstance();
        if ($auth->hasIdentity() == false) {
            echo json_encode(array(
                'response' => 'error',
                'type' => 'login',
                'message' => 'Autenticazione richiesta'
            ));
            exit;
        }
        return $auth->getIdentity();
    }

    private function isAllowed($identity) {
        $acl = Zend_Registry::getInstance()->get('acl');
        $role = strtolower($identity->Role);
        return $acl->isAllowed($role, 'cart');
    }

    private function getDb() {
        $registry = Zend_Registry::getInstance();
        $db = $registry['DB'];
        try {
            $db->getConnection();
        } catch (Zend_Exception $e) {
            header("Content-type: application/json");
            echo json_encode(array(
                'response' => 'error',
                'type' => 'database connection',
                'message' => $e->getMessage()
            ));
            exit;
        }
        $db->query("SET NAMES 'utf8'");
        $db->setFetchMode(Zend_Db::FETCH_ASSOC);
        return $db;
    }

    /**
     * Legge parametri dal body JSON o dalla request
     */
    private function getJsonParam($name, $default = null) {
        static $jsonData = null;
        if ($jsonData === null) {
            $rawBody = file_get_contents('php://input');
            $jsonData = json_decode($rawBody, true) ?: [];
        }
        if (isset($jsonData[$name])) {
            return $jsonData[$name];
        }
        $param = $this->getRequest()->getParam($name);
        return ($param !== null) ? $param : $default;
    }

    /**
     * GET /cart/items
     * Lista items nel carrello per un paziente
     *
     * Params: patientID, doctorID (opzionale)
     */
    public function itemsAction()
    {
        $patientID = $this->getJsonParam('patientID');
        $doctorID = $this->getJsonParam('doctorID');

        if (empty($patientID)) {
            echo json_encode(['response' => 'error', 'message' => 'patientID required']);
            return;
        }

        try {
            $select = $this->db->select()
                ->from(['c' => 'InvoiceCart'])
                ->joinLeft(['p' => 'Patient'], 'c.PatientID = p.ID', ['PatientName' => new Zend_Db_Expr("CONCAT(p.FirstName, ' ', p.LastName)")])
                ->where('c.PatientID = ?', $patientID)
                ->where('c.Status = ?', 'pending')
                ->order('c.CreatedDate DESC');

            if (!empty($doctorID)) {
                $select->where('c.DoctorID = ?', $doctorID);
            }

            $items = $this->db->fetchAll($select);

            // DEBUG: costruisci info per visualizzazione
            $debugSelect = [];
            foreach ($items as $item) {
                $debugSelect[] = [
                    'ID' => $item['ID'],
                    'ServiceDate' => $item['ServiceDate'] ?? 'NULL',
                    'DoctorName' => $item['DoctorName'] ?? 'NULL',
                    'LocationName' => $item['LocationName'] ?? 'NULL',
                    'ActivityName' => $item['ActivityName'] ?? 'NULL'
                ];
            }

            // Calcola totali
            $totalAmount = 0;
            $totalExempt = 0;
            $totalTaxable = 0;
            $totalVAT = 0;

            foreach ($items as &$item) {
                $lineTotal = floatval($item['Amount']) * intval($item['Quantity']);
                $totalAmount += $lineTotal;

                if ($item['VATExempt'] == 1) {
                    $totalExempt += $lineTotal;
                } else {
                    $totalTaxable += $lineTotal;
                    $totalVAT += $lineTotal * floatval($item['VATRate']) / 100;
                }
            }

            echo json_encode([
                'response' => 'success',
                'items' => $items,
                'totals' => [
                    'itemCount' => count($items),
                    'totalAmount' => round($totalAmount, 2),
                    'totalExempt' => round($totalExempt, 2),
                    'totalTaxable' => round($totalTaxable, 2),
                    'totalVAT' => round($totalVAT, 2),
                    'grandTotal' => round($totalAmount + $totalVAT, 2)
                ],
                'DEBUG_SELECT' => $debugSelect
            ]);

        } catch (Exception $e) {
            echo json_encode(['response' => 'error', 'message' => $e->getMessage()]);
        }
    }

    /**
     * POST /cart/add
     * Aggiunge item al carrello
     *
     * Params: patientID, doctorID, description, amount, quantity, vatExempt, vatRate,
     *         appointmentID, journalID, serviceCode, medProcedurePlanID, activityTypeID
     */
    public function addAction()
    {
        // DEBUG: Log raw input
        $rawBody = file_get_contents('php://input');
        error_log("[CART-ADD] Raw body: " . $rawBody);

        $patientID = $this->getJsonParam('patientID');
        $doctorID = $this->getJsonParam('doctorID');
        $description = $this->getJsonParam('description');
        $amount = $this->getJsonParam('amount');

        // DEBUG: Log traceability params
        $serviceDate = $this->getJsonParam('serviceDate');
        $doctorName = $this->getJsonParam('doctorName');
        $locationName = $this->getJsonParam('locationName');
        $activityName = $this->getJsonParam('activityName');
        error_log("[CART-ADD] Traceability: serviceDate='$serviceDate', doctorName='$doctorName', locationName='$locationName', activityName='$activityName'");

        if (empty($patientID) || empty($doctorID) || empty($description) || $amount === null) {
            echo json_encode(['response' => 'error', 'message' => 'Missing required fields: patientID, doctorID, description, amount']);
            return;
        }

        try {
            $data = [
                'PatientID' => $patientID,
                'DoctorID' => $doctorID,
                'Description' => $description,
                'Amount' => floatval($amount),
                'Quantity' => intval($this->getJsonParam('quantity', 1)),
                'VATExempt' => intval($this->getJsonParam('vatExempt', 1)),
                'VATRate' => floatval($this->getJsonParam('vatRate', 0)),
                'Status' => 'pending'
            ];

            // Campi opzionali
            $optionalFields = ['AppointmentID', 'JournalID', 'ServiceCode', 'MedProcedurePlanID', 'ActivityTypeID',
                               'ServiceDate', 'DoctorName', 'LocationName', 'ActivityName'];
            foreach ($optionalFields as $field) {
                $value = $this->getJsonParam(lcfirst($field));
                if (!empty($value)) {
                    $data[$field] = $value;
                }
            }

            $this->db->insert('InvoiceCart', $data);
            $cartID = $this->db->lastInsertId();

            // Conta items per questo paziente
            $count = $this->db->fetchOne(
                "SELECT COUNT(*) FROM InvoiceCart WHERE PatientID = ? AND Status = 'pending'",
                [$patientID]
            );

            echo json_encode([
                'response' => 'success',
                'message' => 'Item aggiunto al carrello',
                'cartID' => $cartID,
                'cartCount' => intval($count),
                'DEBUG_INSERT' => $data
            ]);

        } catch (Exception $e) {
            echo json_encode(['response' => 'error', 'message' => $e->getMessage()]);
        }
    }

    /**
     * POST /cart/remove
     * Rimuove item dal carrello
     *
     * Params: cartID
     */
    public function removeAction()
    {
        $cartID = $this->getJsonParam('cartID');

        if (empty($cartID)) {
            echo json_encode(['response' => 'error', 'message' => 'cartID required']);
            return;
        }

        try {
            // Ottieni patientID prima di eliminare
            $item = $this->db->fetchRow("SELECT PatientID FROM InvoiceCart WHERE ID = ?", [$cartID]);

            $this->db->delete('InvoiceCart', ['ID = ?' => $cartID, 'Status = ?' => 'pending']);

            // Conta items rimanenti
            $count = 0;
            if ($item) {
                $count = $this->db->fetchOne(
                    "SELECT COUNT(*) FROM InvoiceCart WHERE PatientID = ? AND Status = 'pending'",
                    [$item['PatientID']]
                );
            }

            echo json_encode([
                'response' => 'success',
                'message' => 'Item rimosso',
                'cartCount' => intval($count)
            ]);

        } catch (Exception $e) {
            echo json_encode(['response' => 'error', 'message' => $e->getMessage()]);
        }
    }

    /**
     * POST /cart/clear
     * Svuota carrello per un paziente
     *
     * Params: patientID, doctorID (opzionale)
     */
    public function clearAction()
    {
        $patientID = $this->getJsonParam('patientID');
        $doctorID = $this->getJsonParam('doctorID');

        if (empty($patientID)) {
            echo json_encode(['response' => 'error', 'message' => 'patientID required']);
            return;
        }

        try {
            $where = ['PatientID = ?' => $patientID, 'Status = ?' => 'pending'];
            if (!empty($doctorID)) {
                $where['DoctorID = ?'] = $doctorID;
            }

            $deleted = $this->db->delete('InvoiceCart', $where);

            echo json_encode([
                'response' => 'success',
                'message' => "Carrello svuotato ($deleted items rimossi)",
                'cartCount' => 0
            ]);

        } catch (Exception $e) {
            echo json_encode(['response' => 'error', 'message' => $e->getMessage()]);
        }
    }

    /**
     * GET /cart/count
     * Conta items nel carrello per un paziente
     *
     * Params: patientID, doctorID (opzionale)
     */
    public function countAction()
    {
        $patientID = $this->getJsonParam('patientID');
        $doctorID = $this->getJsonParam('doctorID');

        if (empty($patientID)) {
            echo json_encode(['response' => 'error', 'message' => 'patientID required']);
            return;
        }

        try {
            $sql = "SELECT COUNT(*) FROM InvoiceCart WHERE PatientID = ? AND Status = 'pending'";
            $params = [$patientID];

            if (!empty($doctorID)) {
                $sql .= " AND DoctorID = ?";
                $params[] = $doctorID;
            }

            $count = $this->db->fetchOne($sql, $params);

            echo json_encode([
                'response' => 'success',
                'cartCount' => intval($count)
            ]);

        } catch (Exception $e) {
            echo json_encode(['response' => 'error', 'message' => $e->getMessage()]);
        }
    }

    /**
     * POST /cart/checkappointment
     * Verifica se un appuntamento è già nel carrello
     *
     * Params: appointmentID, patientID, doctorID
     * Returns: isInCart (bool), items (array di items collegati all'appuntamento)
     */
    public function checkappointmentAction()
    {
        $appointmentID = $this->getJsonParam('appointmentID');
        $patientID = $this->getJsonParam('patientID');
        $doctorID = $this->getJsonParam('doctorID');

        if (empty($appointmentID)) {
            echo json_encode(['response' => 'error', 'message' => 'appointmentID required']);
            return;
        }

        try {
            $select = $this->db->select()
                ->from('InvoiceCart')
                ->where('AppointmentID = ?', $appointmentID)
                ->where("Status = 'pending'");

            if (!empty($patientID)) {
                $select->where('PatientID = ?', $patientID);
            }
            if (!empty($doctorID)) {
                $select->where('DoctorID = ?', $doctorID);
            }

            $items = $this->db->fetchAll($select);

            echo json_encode([
                'response' => 'success',
                'isInCart' => count($items) > 0,
                'itemCount' => count($items),
                'items' => $items
            ]);

        } catch (Exception $e) {
            echo json_encode(['response' => 'error', 'message' => $e->getMessage()]);
        }
    }

    /**
     * POST /cart/createinvoice
     * Genera fattura o ricevuta da carrello
     *
     * Params: patientID, doctorID, billingEntityID (opzionale), patientBillingInfoID (opzionale), documentType (invoice/receipt)
     */
    public function createinvoiceAction()
    {
        $patientID = $this->getJsonParam('patientID');
        $doctorID = $this->getJsonParam('doctorID');
        $billingEntityID = $this->getJsonParam('billingEntityID');
        $patientBillingInfoID = $this->getJsonParam('patientBillingInfoID');
        $documentType = $this->getJsonParam('documentType', 'invoice');  // Default: invoice (fattura)

        if (empty($patientID) || empty($doctorID)) {
            echo json_encode(['response' => 'error', 'message' => 'patientID and doctorID required']);
            return;
        }

        try {
            // Recupera items dal carrello
            $items = $this->db->fetchAll(
                "SELECT * FROM InvoiceCart WHERE PatientID = ? AND DoctorID = ? AND Status = 'pending'",
                [$patientID, $doctorID]
            );

            if (empty($items)) {
                echo json_encode(['response' => 'error', 'message' => 'Carrello vuoto']);
                return;
            }

            // Calcola totali
            $total = 0;
            $totalExempt = 0;
            $totalTaxable = 0;
            $totalVAT = 0;

            foreach ($items as $item) {
                $lineTotal = floatval($item['Amount']) * intval($item['Quantity']);
                $total += $lineTotal;

                if ($item['VATExempt'] == 1) {
                    $totalExempt += $lineTotal;
                } else {
                    $totalTaxable += $lineTotal;
                    $totalVAT += $lineTotal * floatval($item['VATRate']) / 100;
                }
            }

            // Ottieni prossimo numero fattura
            $year = date('Y');
            $lastNumber = $this->db->fetchOne(
                "SELECT MAX(CAST(InvoiceNumber AS UNSIGNED)) FROM Invoice WHERE DoctorID = ? AND YEAR(InvoiceDate) = ?",
                [$doctorID, $year]
            );
            $nextNumber = intval($lastNumber) + 1;

            // Genera UUID per LogID
            $logID = $this->db->fetchOne("SELECT UUID()");

            // Crea fattura o ricevuta
            $invoiceData = [
                'InvoiceNumber' => $nextNumber,
                'InvoiceDate' => date('Y-m-d'),
                'DoctorID' => $doctorID,
                'PatientID' => $patientID,
                'TotalAmount' => round($total + $totalVAT, 2),
                'TotalTaxable' => round($totalTaxable, 2),
                'TotalVAT' => round($totalVAT, 2),
                'TotalExempt' => round($totalExempt, 2),
                'Closed' => 0,
                'Enabled' => 1,
                'DateSort' => date('Y-m-d'),
                'LogID' => $logID,
                'DocumentType' => $documentType  // 'invoice' = fattura, 'receipt' = ricevuta
            ];

            // Campi opzionali
            if (!empty($billingEntityID)) {
                $invoiceData['BillingEntityID'] = $billingEntityID;
            }
            if (!empty($patientBillingInfoID)) {
                $invoiceData['PatientBillingInfoID'] = $patientBillingInfoID;
            }

            // Marca da bollo automatica (€2 se esente > €77.47)
            if ($totalExempt > 77.47) {
                $invoiceData['StampDuty'] = 2.00;
                $invoiceData['TotalAmount'] = round($total + $totalVAT + 2.00, 2);
            }

            $this->db->insert('Invoice', $invoiceData);
            $invoiceID = $this->db->lastInsertId();

            // Crea righe fattura
            foreach ($items as $item) {
                $rowData = [
                    'InvoiceID' => $invoiceID,
                    'Description' => $item['Description'],
                    'Amount' => $item['Amount'],
                    'VATExempt' => $item['VATExempt'],
                    'VATRate' => $item['VATRate'],
                    'VATAmount' => $item['VATExempt'] == 0 ? round(floatval($item['Amount']) * floatval($item['VATRate']) / 100, 2) : 0
                ];

                if (!empty($item['MedProcedurePlanID'])) {
                    $rowData['MedProcedurePlanID'] = $item['MedProcedurePlanID'];
                }

                $this->db->insert('InvoiceRow', $rowData);
            }

            // Inserisci record Log
            $this->db->insert('Log', [
                'UniqueID' => $logID,
                'UserID' => $doctorID,
                'Date' => date('Y-m-d H:i:s'),
                'Action' => 'create'
            ]);

            // Aggiorna stato items carrello
            $this->db->update('InvoiceCart',
                ['Status' => 'invoiced', 'InvoiceID' => $invoiceID],
                ['PatientID = ?' => $patientID, 'DoctorID = ?' => $doctorID, 'Status = ?' => 'pending']
            );

            // Collega eventuali pagamenti pending alla fattura
            $paymentsLinked = 0;
            $pendingPayments = $this->db->fetchAll(
                "SELECT ID FROM CartPayment WHERE PatientID = ? AND DoctorID = ? AND Status = 'pending' AND InvoiceID IS NULL",
                [$patientID, $doctorID]
            );
            if (!empty($pendingPayments)) {
                foreach ($pendingPayments as $payment) {
                    $this->db->update('CartPayment',
                        ['InvoiceID' => $invoiceID, 'Status' => 'completed'],
                        ['ID = ?' => $payment['ID']]
                    );
                    $paymentsLinked++;
                }
            }

            $docTypeLabel = ($documentType === 'receipt') ? 'Ricevuta' : 'Fattura';
            echo json_encode([
                'response' => 'success',
                'message' => $docTypeLabel . ' creata con successo',
                'invoiceID' => $invoiceID,
                'invoiceNumber' => $nextNumber,
                'documentType' => $documentType,
                'total' => $invoiceData['TotalAmount'],
                'itemCount' => count($items),
                'paymentsLinked' => $paymentsLinked
            ]);

        } catch (Exception $e) {
            echo json_encode(['response' => 'error', 'message' => $e->getMessage()]);
        }
    }

    /**
     * POST /cart/update
     * Aggiorna item nel carrello (quantità, importo, etc.)
     *
     * Params: cartID, amount, quantity, description
     */
    public function updateAction()
    {
        $cartID = $this->getJsonParam('cartID');

        if (empty($cartID)) {
            echo json_encode(['response' => 'error', 'message' => 'cartID required']);
            return;
        }

        try {
            $data = [];

            $updateFields = ['amount' => 'Amount', 'quantity' => 'Quantity', 'description' => 'Description',
                             'vatExempt' => 'VATExempt', 'vatRate' => 'VATRate',
                             'serviceDate' => 'ServiceDate', 'doctorName' => 'DoctorName',
                             'locationName' => 'LocationName', 'activityName' => 'ActivityName'];

            foreach ($updateFields as $param => $column) {
                $value = $this->getJsonParam($param);
                if ($value !== null && $value !== '') {
                    if (in_array($column, ['Amount', 'VATRate'])) {
                        $data[$column] = floatval($value);
                    } elseif (in_array($column, ['Quantity', 'VATExempt'])) {
                        $data[$column] = intval($value);
                    } else {
                        $data[$column] = $value;
                    }
                }
            }

            if (empty($data)) {
                echo json_encode(['response' => 'error', 'message' => 'No fields to update']);
                return;
            }

            $this->db->update('InvoiceCart', $data, ['ID = ?' => $cartID, 'Status = ?' => 'pending']);

            echo json_encode([
                'response' => 'success',
                'message' => 'Item aggiornato'
            ]);

        } catch (Exception $e) {
            echo json_encode(['response' => 'error', 'message' => $e->getMessage()]);
        }
    }
}
