<?php
/**
 * Complete Invoices Controller
 * Generate, export, and manage invoices
 */

class InvoicesController {
    private $db;
    private $config;

    public function __construct($db, $config) {
        $this->db = $db;
        $this->config = $config;
    }

    /**
     * GET /api/invoices
     * Get all invoices with filters
     */
    public function getAll($filters = []) {
        try {
            $query = "
                SELECT 
                    i.id, i.invoice_number, i.booking_id, i.guest_id,
                    i.property_id, i.amount, i.tax_amount, i.total,
                    i.status, i.due_date, i.issued_date, i.paid_date,
                    b.check_in, b.check_out, b.nights,
                    g.name as guest_name, g.email as guest_email,
                    p.name as property_name
                FROM folio_charges i
                JOIN bookings b ON i.booking_id = b.id
                JOIN guests g ON b.guest_id = g.id
                JOIN properties p ON b.property_id = p.id
                WHERE 1=1
            ";

            $params = [];

            if (!empty($filters['property_id'])) {
                $query .= " AND i.property_id = ?";
                $params[] = $filters['property_id'];
            }

            if (!empty($filters['status'])) {
                $query .= " AND i.status = ?";
                $params[] = $filters['status'];
            }

            if (!empty($filters['guest_id'])) {
                $query .= " AND b.guest_id = ?";
                $params[] = $filters['guest_id'];
            }

            $query .= " ORDER BY i.issued_date DESC";

            $stmt = $this->db->prepare($query);
            $stmt->execute($params);
            $invoices = $stmt->fetchAll(PDO::FETCH_ASSOC);

            return [
                'success' => true,
                'count' => count($invoices),
                'invoices' => $invoices
            ];

        } catch (Exception $e) {
            error_log('Error fetching invoices: ' . $e->getMessage());
            return ['success' => false, 'message' => 'Error fetching invoices'];
        }
    }

    /**
     * GET /api/invoices/{id}
     * Get single invoice with details
     */
    public function getById($id) {
        try {
            $stmt = $this->db->prepare("
                SELECT 
                    i.*, 
                    b.booking_reference, b.check_in, b.check_out, b.nights, b.price as room_charge,
                    g.name as guest_name, g.email as guest_email, g.address as guest_address, g.phone as guest_phone,
                    p.name as property_name, p.address as property_address, p.tax_rate
                FROM folio_charges i
                JOIN bookings b ON i.booking_id = b.id
                JOIN guests g ON b.guest_id = g.id
                JOIN properties p ON b.property_id = p.id
                WHERE i.id = ?
            ");
            $stmt->execute([$id]);
            $invoice = $stmt->fetch(PDO::FETCH_ASSOC);

            if (!$invoice) {
                return ['success' => false, 'message' => 'Invoice not found'];
            }

            return ['success' => true, 'invoice' => $invoice];

        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error fetching invoice'];
        }
    }

    /**
     * POST /api/invoices
     * Generate invoice from booking
     */
    public function generate($booking_id, $user_id = null) {
        try {
            // Get booking details
            $stmt = $this->db->prepare("
                SELECT b.*, p.tax_rate, p.service_charge
                FROM bookings b
                JOIN properties p ON b.property_id = p.id
                WHERE b.id = ?
            ");
            $stmt->execute([$booking_id]);
            $booking = $stmt->fetch(PDO::FETCH_ASSOC);

            if (!$booking) {
                return ['success' => false, 'message' => 'Booking not found'];
            }

            // Check if invoice already exists
            $stmt = $this->db->prepare("
                SELECT id FROM folio_charges 
                WHERE booking_id = ? AND type = 'room_charge'
            ");
            $stmt->execute([$booking_id]);
            if ($stmt->fetch()) {
                return ['success' => false, 'message' => 'Invoice already exists for this booking'];
            }

            // Calculate amounts
            $room_charge = $booking['price'];
            $tax_rate = $booking['tax_rate'] ?? 10;
            $service_charge = $booking['service_charge'] ?? 0;
            
            $tax_amount = round($room_charge * ($tax_rate / 100), 2);
            $total = $room_charge + $tax_amount + $service_charge;

            // Generate invoice number
            $invoice_number = 'INV-' . date('Ym') . '-' . str_pad(
                $this->getNextInvoiceSequence($booking['property_id']),
                5,
                '0',
                STR_PAD_LEFT
            );

            // Create invoice
            $stmt = $this->db->prepare("
                INSERT INTO folio_charges (
                    booking_id, guest_id, property_id, type, 
                    description, amount, tax_amount, total,
                    status, issued_date, due_date, created_at, updated_at
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 7 DAY), NOW(), NOW())
            ");

            $stmt->execute([
                $booking_id,
                $booking['guest_id'],
                $booking['property_id'],
                'room_charge',
                'Room charges for ' . $booking['nights'] . ' nights',
                $room_charge,
                $tax_amount,
                $total
            ]);

            $invoice_id = $this->db->lastInsertId();

            // Store invoice number
            $stmt = $this->db->prepare("UPDATE folio_charges SET invoice_number = ? WHERE id = ?");
            $stmt->execute([$invoice_number, $invoice_id]);

            // Log activity
            $this->logActivity($user_id, 'invoice.generate', 'invoice', $invoice_id, $invoice_number);

            // Queue invoice email
            $this->queueEmail([
                'type' => 'invoice_generated',
                'invoice_id' => $invoice_id,
                'booking_id' => $booking_id
            ]);

            return [
                'success' => true,
                'message' => 'Invoice generated',
                'invoice_id' => $invoice_id,
                'invoice_number' => $invoice_number,
                'total' => $total
            ];

        } catch (Exception $e) {
            error_log('Error generating invoice: ' . $e->getMessage());
            return ['success' => false, 'message' => 'Error generating invoice'];
        }
    }

    /**
     * POST /api/invoices/{id}/payment
     * Mark invoice as paid
     */
    public function markPaid($invoice_id, $payment_data) {
        try {
            $stmt = $this->db->prepare("
                UPDATE folio_charges 
                SET status = 'paid', paid_date = NOW()
                WHERE id = ?
            ");
            $stmt->execute([$invoice_id]);

            // Create payment record
            $stmt = $this->db->prepare("
                INSERT INTO payments (
                    booking_id, amount, payment_method, 
                    status, transaction_id, created_at
                ) SELECT booking_id, total, ?, 'completed', ?, NOW()
                FROM folio_charges WHERE id = ?
            ");

            $stmt->execute([
                $payment_data['method'] ?? 'stripe',
                $payment_data['transaction_id'] ?? null,
                $invoice_id
            ]);

            return ['success' => true, 'message' => 'Invoice marked as paid'];

        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error updating payment'];
        }
    }

    /**
     * POST /api/invoices/{id}/export-csv
     * Export invoice as CSV
     */
    public function exportCSV($invoice_id) {
        try {
            $result = $this->getById($invoice_id);
            if (!$result['success']) {
                return $result;
            }

            $invoice = $result['invoice'];

            // Build CSV content
            $csv = "HOSTIVA - INVOICE REPORT\n";
            $csv .= "Generated: " . date('Y-m-d H:i:s') . "\n\n";

            $csv .= "INVOICE DETAILS\n";
            $csv .= "Invoice #," . $invoice['invoice_number'] . "\n";
            $csv .= "Status," . strtoupper($invoice['status']) . "\n";
            $csv .= "Issued Date," . date('Y-m-d', strtotime($invoice['issued_date'])) . "\n";
            $csv .= "Due Date," . date('Y-m-d', strtotime($invoice['due_date'])) . "\n\n";

            $csv .= "PROPERTY\n";
            $csv .= "Property Name," . $invoice['property_name'] . "\n";
            $csv .= "Address," . $invoice['property_address'] . "\n\n";

            $csv .= "GUEST\n";
            $csv .= "Guest Name," . $invoice['guest_name'] . "\n";
            $csv .= "Email," . $invoice['guest_email'] . "\n";
            $csv .= "Phone," . $invoice['guest_phone'] . "\n";
            $csv .= "Address," . $invoice['guest_address'] . "\n\n";

            $csv .= "BOOKING DETAILS\n";
            $csv .= "Booking Reference," . $invoice['booking_reference'] . "\n";
            $csv .= "Check-In," . date('Y-m-d', strtotime($invoice['check_in'])) . "\n";
            $csv .= "Check-Out," . date('Y-m-d', strtotime($invoice['check_out'])) . "\n";
            $csv .= "Nights," . $invoice['nights'] . "\n\n";

            $csv .= "CHARGES\n";
            $csv .= "Room Charge (per night)," . number_format($invoice['amount'] / $invoice['nights'], 2) . "\n";
            $csv .= "Room Charge (total)," . number_format($invoice['amount'], 2) . "\n";
            $csv .= "Tax Rate," . ($invoice['tax_rate'] ?? 10) . "%\n";
            $csv .= "Tax Amount," . number_format($invoice['tax_amount'], 2) . "\n";
            $csv .= "Service Charge," . number_format(($invoice['total'] - $invoice['amount'] - $invoice['tax_amount']), 2) . "\n";
            $csv .= "TOTAL," . number_format($invoice['total'], 2) . "\n\n";

            if ($invoice['status'] === 'paid' && $invoice['paid_date']) {
                $csv .= "PAYMENT\n";
                $csv .= "Payment Date," . date('Y-m-d', strtotime($invoice['paid_date'])) . "\n";
            }

            return [
                'success' => true,
                'csv' => $csv,
                'filename' => 'Invoice-' . $invoice['invoice_number'] . '-' . date('Y-m-d') . '.csv'
            ];

        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error exporting invoice'];
        }
    }

    /**
     * POST /api/invoices/export-all
     * Export all invoices as CSV
     */
    public function exportAllCSV($filters = []) {
        try {
            $result = $this->getAll($filters);
            if (!$result['success']) {
                return $result;
            }

            $invoices = $result['invoices'];

            // Build CSV
            $csv = "Invoice #,Guest,Property,Issue Date,Amount,Tax,Total,Status\n";

            foreach ($invoices as $inv) {
                $csv .= sprintf(
                    "\"%s\",\"%s\",\"%s\",%s,%s,%s,%s,%s\n",
                    $inv['invoice_number'],
                    $inv['guest_name'],
                    $inv['property_name'],
                    date('Y-m-d', strtotime($inv['issued_date'])),
                    number_format($inv['amount'], 2),
                    number_format($inv['tax_amount'], 2),
                    number_format($inv['total'], 2),
                    $inv['status']
                );
            }

            // Summary
            $csv .= "\n\nSUMMARY\n";
            $csv .= "Total Invoices," . count($invoices) . "\n";

            $totals = array_reduce($invoices, function($carry, $inv) {
                $carry['amount'] += $inv['amount'];
                $carry['tax'] += $inv['tax_amount'];
                $carry['total'] += $inv['total'];
                if ($inv['status'] === 'paid') $carry['paid'] += $inv['total'];
                return $carry;
            }, ['amount' => 0, 'tax' => 0, 'total' => 0, 'paid' => 0]);

            $csv .= "Total Amount," . number_format($totals['amount'], 2) . "\n";
            $csv .= "Total Tax," . number_format($totals['tax'], 2) . "\n";
            $csv .= "Grand Total," . number_format($totals['total'], 2) . "\n";
            $csv .= "Total Paid," . number_format($totals['paid'], 2) . "\n";
            $csv .= "Outstanding," . number_format($totals['total'] - $totals['paid'], 2) . "\n";

            return [
                'success' => true,
                'csv' => $csv,
                'filename' => 'Invoices-Report-' . date('Y-m-d') . '.csv'
            ];

        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error exporting invoices'];
        }
    }

    /**
     * Helper: Get next invoice sequence
     */
    private function getNextInvoiceSequence($property_id) {
        try {
            $stmt = $this->db->prepare("
                SELECT MAX(CAST(SUBSTRING(invoice_number, -5) AS UNSIGNED)) as seq
                FROM folio_charges
                WHERE property_id = ? AND invoice_number LIKE ?
            ");
            $stmt->execute([$property_id, date('Ym') . '-%']);
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            return ($result['seq'] ?? 0) + 1;
        } catch (Exception $e) {
            return 1;
        }
    }

    /**
     * Helper: Queue email
     */
    private function queueEmail($email_data) {
        try {
            $stmt = $this->db->prepare("
                INSERT INTO event_queue (event_type, data, status, created_at)
                VALUES (?, ?, 'pending', NOW())
            ");
            $stmt->execute(['email', json_encode($email_data)]);
        } catch (Exception $e) {
            error_log('Error queuing email: ' . $e->getMessage());
        }
    }

    /**
     * Helper: Log activity
     */
    private function logActivity($user_id, $action, $entity_type, $entity_id, $description = null) {
        try {
            $stmt = $this->db->prepare("
                INSERT INTO activity_log (user_id, action, entity_type, entity_id, description, ip, user_agent)
                VALUES (?, ?, ?, ?, ?, ?, ?)
            ");
            $stmt->execute([
                $user_id,
                $action,
                $entity_type,
                $entity_id,
                $description,
                $_SERVER['REMOTE_ADDR'] ?? '',
                $_SERVER['HTTP_USER_AGENT'] ?? ''
            ]);
        } catch (Exception $e) {
            error_log('Error logging activity: ' . $e->getMessage());
        }
    }
}
