<?php

declare(strict_types=1);

require_once __DIR__ . '/helpers.php';
require_once __DIR__ . '/db.php';
require_once __DIR__ . '/Client.php';
require_once __DIR__ . '/Template.php';
require_once __DIR__ . '/Module.php';
require_once __DIR__ . '/Auth/AuthManager.php';
require_once __DIR__ . '/MultiTenant/TenantManager.php';
require_once __DIR__ . '/FileManager.php';
require_once __DIR__ . '/../vendor/autoload.php';

use Dompdf\Dompdf;
use Dompdf\Options;

class Proposal
{
    private static function generateProposalNumber(int $companyId): string
    {
        $pdo = getPDO();
        $stmt = $pdo->prepare('SELECT COUNT(*) as count FROM proposals WHERE company_id = ?');
        $stmt->execute([$companyId]);
        $count = (int) $stmt->fetch()['count'];
        
        return 'PRO-' . ($count + 1);
    }

    public static function create(array $data): int
    {
        $companyId = TenantDB::getTenant();
        if (!$companyId) {
            throw new Exception('No company context available');
        }
        
        // Check if user can create more proposals based on plan limits
        if (!TenantManager::canPerformAction('proposals_per_month', 1)) {
            throw new Exception('You have reached the proposal limit for your plan. Upgrade to create more proposals.');
        }
        
        $pdo = getPDO();
        $proposalNumber = self::generateProposalNumber($companyId);
        $stmt = $pdo->prepare('INSERT INTO proposals (company_id, client_id, template_id, title, proposal_number, modules_json, variables_json, pricing_json, currency, status, created_at) VALUES (:company_id, :client_id, :template_id, :title, :proposal_number, :modules_json, :variables_json, :pricing_json, :currency, :status, :created_at)');
        $stmt->execute([
            ':company_id' => $companyId,
            ':client_id' => $data['client_id'],
            ':template_id' => $data['template_id'],
            ':title' => $data['title'] ?? 'Proposal #' . ($data['proposal_id'] ?? 'New'),
            ':proposal_number' => $proposalNumber,
            ':modules_json' => json_encode($data['modules_json'] ?? []),
            ':variables_json' => json_encode($data['variables_json'] ?? []),
            ':pricing_json' => json_encode($data['pricing_json'] ?? []),
            ':currency' => $data['currency'] ?? 'USD',
            ':status' => $data['status'] ?? 'draft',
            ':created_at' => date('c'),
        ]);

        return (int) $pdo->lastInsertId();
    }

    public static function find(int $id): ?array
    {
        $pdo = getPDO();
        $stmt = $pdo->prepare('SELECT * FROM proposals WHERE id = :id');
        $stmt->execute([':id' => $id]);
        $row = $stmt->fetch();

        if (!$row) {
            return null;
        }

        // Check if user has access to this proposal
        $companyId = TenantDB::getTenant();
        if ($row['company_id'] != $companyId) {
            throw new Exception('Access denied: Proposal not found in your workspace');
        }

        $row['modules_json'] = json_decode($row['modules_json'] ?? '[]', true);
        $row['variables_json'] = json_decode($row['variables_json'] ?? '{}', true);
        $row['pricing_json'] = json_decode($row['pricing_json'] ?? '[]', true);

        return $row;
    }

    public static function all(): array
    {
        // Get workspace from URL parameter or session
        $workspace = $_GET['workspace'] ?? $_SESSION['workspace'] ?? null;
        if (!$workspace || is_array($workspace)) {
            return [];
        }
        
        $pdo = getPDO();
        
        // Get company from workspace
        $stmt = $pdo->prepare('SELECT * FROM companies WHERE username = ?');
        $stmt->execute([$workspace]);
        $company = $stmt->fetch();
        
        if (!$company) {
            return [];
        }
        
        $stmt = $pdo->prepare('SELECT * FROM proposals WHERE company_id = :company_id ORDER BY created_at DESC');
        $stmt->execute([':company_id' => $company['id']]);
        $all = $stmt->fetchAll();

        foreach ($all as &$row) {
            $row['modules_json'] = json_decode($row['modules_json'] ?? '[]', true);
            $row['variables_json'] = json_decode($row['variables_json'] ?? '{}', true);
            $row['pricing_json'] = json_decode($row['pricing_json'] ?? '[]', true);
        }

        return $all;
    }

    public static function delete(int $id): void
    {
        $companyId = TenantDB::getTenant();
        if (!$companyId) {
            throw new Exception('No company context available');
        }
        
        $pdo = getPDO();
        $stmt = $pdo->prepare('DELETE FROM proposals WHERE id = :id AND company_id = :company_id');
        $stmt->execute([':id' => $id, ':company_id' => $companyId]);
        
        // Check if deletion was successful
        if ($stmt->rowCount() === 0) {
            throw new Exception('Proposal not found or access denied');
        }
    }

    public static function update(int $id, array $data): void
    {
        $pdo = getPDO();
        $fields = [];
        $values = [':id' => $id];

        if (isset($data['title'])) {
            $fields[] = 'title = :title';
            $values[':title'] = $data['title'];
        }
        if (isset($data['status'])) {
            $fields[] = 'status = :status';
            $values[':status'] = $data['status'];
        }
        if (isset($data['pdf_path'])) {
            $fields[] = 'pdf_path = :pdf_path';
            $values[':pdf_path'] = $data['pdf_path'];
        }
        if (isset($data['modules_json'])) {
            $fields[] = 'modules_json = :modules_json';
            $values[':modules_json'] = json_encode($data['modules_json']);
        }
        if (isset($data['variables_json'])) {
            $fields[] = 'variables_json = :variables_json';
            $values[':variables_json'] = json_encode($data['variables_json']);
        }
        if (isset($data['pricing_json'])) {
            $fields[] = 'pricing_json = :pricing_json';
            $values[':pricing_json'] = json_encode($data['pricing_json']);
        }
        if (isset($data['currency'])) {
            $fields[] = 'currency = :currency';
            $values[':currency'] = $data['currency'];
        }

        if (!empty($fields)) {
            $sql = 'UPDATE proposals SET ' . implode(', ', $fields) . ' WHERE id = :id';
            $stmt = $pdo->prepare($sql);
            $stmt->execute($values);
        }
    }

    public static function generatePdf(int $id): string
    {
        $proposal = self::find($id);
        if (!$proposal) {
            throw new Exception('Proposal not found');
        }

        // Get client and template data
        $client = Client::find($proposal['client_id']);
        $template = Template::find($proposal['template_id']);
        if (!$client || !$template) {
            throw new Exception('Client or template not found');
        }

        // Get modules data from template first, then override with proposal data
        $templateModules = $template['modules_json'] ?? [];
        $proposalModules = $proposal['modules_json'] ?? [];
        
        // If proposal has modules, use those; otherwise use template modules
        $modules = !empty($proposalModules) ? $proposalModules : $templateModules;
        
        $debugInfo[] = 'Template modules: ' . json_encode($templateModules);
        $debugInfo[] = 'Proposal modules: ' . json_encode($proposalModules);
        $debugInfo[] = 'Using modules: ' . json_encode($modules);
        $variables = $proposal['variables_json'] ?? [];
        $pricing = $proposal['pricing_json'] ?? [];
        $currency = $proposal['currency'] ?? 'USD';

        // Build variables array for template replacement
        $templateVariables = array_merge($variables, [
            'client_name' => $client['name'] ?? '',
            'company_name' => $client['company'] ?? '',
            'project_name' => $proposal['title'] ?? '',
            'proposal_number' => $proposal['proposal_number'] ?? 'PRO-' . $proposal['id'],
            'proposal_date' => date('F j, Y', strtotime($proposal['created_at'] ?? 'now')),
            'client_email' => $client['email'] ?? '',
            'client_phone' => $client['phone'] ?? '',
            'client_address' => $client['address'] ?? '',
        ]);

        // Get attached modules with full details
        $attachedModules = [];
        $debugInfo[] = 'Raw modules data: ' . json_encode($modules);
        foreach ($modules as $index => $moduleData) {
            $debugInfo[] = 'Processing module ' . $index . ': ' . json_encode($moduleData);
            $isEnabled = $moduleData['enabled'] ?? false;
            $debugInfo[] = 'Module ' . ($moduleData['module_id'] ?? 'unknown') . ' enabled status: ' . ($isEnabled ? 'TRUE' : 'FALSE');
            
            if ($isEnabled) {
                $module = Module::find($moduleData['module_id']);
                $debugInfo[] = 'Found module: ' . json_encode($module);
                
                $content = $moduleData['content_html'] ?? '';
                $debugInfo[] = 'Module content length: ' . strlen($content);
                $debugInfo[] = 'Module content preview: ' . substr($content, 0, 100) . '...';
                
                // Use module name from database if available, otherwise use generic name
                $moduleName = 'Module ' . ($moduleData['module_id'] ?? 'Unknown');
                if ($module && !empty($module['title'])) {
                    $moduleName = $module['title'];
                }
                
                $attachedModules[] = [
                    'id' => $moduleData['module_id'] ?? 0,
                    'name' => $moduleName,
                    'content_html' => $content,
                    'sort_order' => $moduleData['sort_order'] ?? 0
                ];
            } else {
                $debugInfo[] = 'Module ' . ($moduleData['module_id'] ?? 'unknown') . ' is DISABLED';
            }
        }
        
        // Convert base64 images to simple data URLs (no complex processing)
        function processImagesForPdf($html) {
            // Handle base64 images - preserve all attributes including size
            $html = preg_replace_callback(
                '/<img([^>]+)src="data:image\/([^;]+);base64,([^"]+)"([^>]*)>/i',
                function($matches) {
                    $attributes = $matches[1]; // attributes before src
                    $imageType = $matches[2];
                    $base64Data = $matches[3];
                    $attributesAfter = $matches[4]; // attributes after src
                    
                    return '<img' . $attributes . 'src="data:image/' . $imageType . ';base64,' . $base64Data . '"' . $attributesAfter . ' />';
                },
                $html
            );
            
            // Handle asset paths - convert to absolute paths
            $html = preg_replace_callback(
                '/<img([^>]+)src="([^"]+)"([^>]*)>/i',
                function($matches) {
                    $attributes = $matches[1]; // attributes before src
                    $src = $matches[2];
                    $attributesAfter = $matches[3]; // attributes after src
                    
                    // If it's a relative asset path, make it absolute
                    if (strpos($src, 'assets/') === 0) {
                        $fullPath = __DIR__ . '/../public/' . $src;
                        if (file_exists($fullPath)) {
                            // Convert to base64 for embedding
                            $imageData = file_get_contents($fullPath);
                            $imageType = pathinfo($fullPath, PATHINFO_EXTENSION) ?: 'png';
                            $base64 = base64_encode($imageData);
                            return '<img' . $attributes . 'src="data:image/' . $imageType . ';base64,' . $base64 . '"' . $attributesAfter . ' />';
                        }
                    }
                    return '<img' . $attributes . 'src="' . $src . '"' . $attributesAfter . ' />';
                },
                $html
            );
            
            return $html;
        }
        
        usort($attachedModules, function($a, $b) {
            return $a['sort_order'] - $b['sort_order'];
        });

        // Generate HTML for PDF
        $html = '<!DOCTYPE html>';
        $html .= '<html><head>';
        $html .= '<meta charset="UTF-8">';
        $html .= '<title>' . h($proposal['title'] ?? 'Proposal') . '</title>';
        $html .= '<style>';
        $html .= '@page { size: A4; margin: 10mm; }';
        $html .= 'body { font-family: Arial, sans-serif; font-size: 12px; line-height: 1.4; margin: 0; padding: 0; width: 190mm; }';
        $html .= '.header { width: 100%; padding: 1mm 0; }';
        $html .= '.footer { position: fixed; bottom: 0; left: 0; right: 0; width: 100%; padding: 2mm 0 8mm 0; border-top: 1px solid #e2e8f0; font-size: 10px; color: #666; }';
        $html .= '.content { width: 100%; padding: 1mm 0 25mm 0; min-height: 200mm; }';
        $html .= '.page-number { position: fixed; bottom: 2mm; left: 0; right: 0; text-align: center; font-size: 9px; color: #666; }';
        $html .= '.page-number:after { content: "Page " counter(page); }';
        $html .= '.client-box { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px; padding: 16px; margin: 20px 0; word-wrap: break-word; overflow-wrap: break-word; }';
        $html .= '.client-box h3 { margin: 0 0 12px 0; font-size: 14px; font-weight: 600; color: #0f172a; }';
        $html .= '.client-box p { margin: 6px 0; font-size: 12px; color: #64748b; word-wrap: break-word; overflow-wrap: break-word; }';
        $html .= '.module { margin-bottom: 20px; page-break-inside: avoid; word-wrap: break-word; overflow-wrap: break-word; }';
        $html .= '.module-content { font-size: 12px; line-height: 1.6; word-wrap: break-word; overflow-wrap: break-word; }';
        $html .= 'img { max-width: 100%; height: auto; display: block; margin: 10px 0; }';
        $html .= 'table { width: 100%; border-collapse: collapse; margin: 10px 0; table-layout: fixed; }';
        $html .= 'table td, table th { border: 1px solid #e2e8f0; padding: 6px; font-size: 11px; word-wrap: break-word; overflow-wrap: break-word; }';
        $html .= 'table th { background: #f8fafc; font-weight: bold; }';
        $html .= '.pricing-table { width: 100%; border-collapse: collapse; margin: 15px 0; table-layout: fixed; }';
        $html .= '.pricing-table th, .pricing-table td { border: 1px solid #e2e8f0; padding: 8px; text-align: left; font-size: 12px; word-wrap: break-word; overflow-wrap: break-word; }';
        $html .= '.pricing-table th { background: #f1f5f9; font-weight: bold; color: #0f172a; }';
        $html .= '.pricing-table .total { background: #e2e8f0; font-weight: bold; }';
        $html .= 'p { word-wrap: break-word; overflow-wrap: break-word; margin: 8px 0; }';
        $html .= 'div { word-wrap: break-word; overflow-wrap: break-word; }';
        $html .= '@page { margin: 10mm; }';
        $html .= '.page-break { page-break-before: always; padding-top: 15mm; }';
        $html .= '</style>';
        $html .= '</head><body>';

        // Header (dynamic height based on content)
        $html .= '<div class="header">';
        $headerContent = renderWithVariables($template['header_html'] ?? '<h1 style="margin: 0; font-size: 10px; font-weight: bold;">' . h($template['name'] ?? 'Proposal') . '</h1>', $templateVariables);
        $headerContent = processImagesForPdf($headerContent);
        $html .= $headerContent; // Don't force center - preserve TinyMCE alignment
        $html .= '</div>';

        // Main content area (defined body area)
        $html .= '<div class="content">';

        // Client information box (no title)
        $html .= '<div class="client-box">';
        if (!empty($client['name'])) {
            $html .= '<p><strong>Name:</strong> ' . h($client['name']) . '</p>';
        }
        if (!empty($client['company'])) {
            $html .= '<p><strong>Company:</strong> ' . h($client['company']) . '</p>';
        }
        if (!empty($client['email'])) {
            $html .= '<p><strong>Email:</strong> ' . h($client['email']) . '</p>';
        }
        if (!empty($client['phone'])) {
            $html .= '<p><strong>Phone:</strong> ' . h($client['phone']) . '</p>';
        }
        if (!empty($client['address'])) {
            $html .= '<p><strong>Address:</strong> ' . h($client['address']) . '</p>';
        }
        
        // Separator line inside box
        if (!empty($client['name']) || !empty($client['company']) || !empty($client['email']) || !empty($client['phone']) || !empty($client['address'])) {
            $html .= '<hr style="margin: 12px 0; border: none; border-top: 1px solid #e2e8f0;">';
        }
        
        $html .= '<p style="margin: 0; font-size: 11px; color: #64748b;">' . h($proposal['proposal_number'] ?? 'PRO-' . $proposal['id']) . ' • Created on ' . date('F jS, Y', strtotime($proposal['created_at'] ?? 'now')) . '</p>';
        $html .= '</div>';

        // Render all modules with proper spacing
        if (!empty($attachedModules)) {
            foreach ($attachedModules as $index => $module) {
                $html .= '<div class="module">';
                
                // Module content only - no title
                if (!empty($module['content_html'])) {
                    $content = renderWithVariables($module['content_html'], $templateVariables);
                    $content = processImagesForPdf($content);
                    $html .= '<div class="module-content">' . $content . '</div>';
                } else {
                    $html .= '<p style="color: #64748b; font-style: italic;">No content available for this module.</p>';
                }
                
                $html .= '</div>';
            }
        } else {
            $html .= '<div class="module">';
            $html .= '<p style="color: #64748b;">No modules have been added to this proposal.</p>';
            $html .= '</div>';
        }

        // Pricing Table
        if (!empty($pricing)) {
            $html .= '<div class="pricing-section">';
            $html .= '<h2 style="margin: 30px 0 15px 0; font-size: 18px; color: #0f172a; border-bottom: 2px solid #e2e8f0; padding-bottom: 8px;">Pricing Details</h2>';
            $html .= '<table class="pricing-table">';
            $html .= '<tr><th>Description</th><th>Quantity</th><th>Unit Price</th><th>Total</th></tr>';
            $total = 0;
            foreach ($pricing as $row) {
                $totalItem = ($row['quantity'] ?? 1) * ($row['unit_price'] ?? 0);
                $total += $totalItem;
                $html .= sprintf(
                    '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>',
                    h($row['description'] ?? ''),
                    (float) ($row['quantity'] ?? 1),
                    formatCurrency((float) ($row['unit_price'] ?? 0), $currency),
                    formatCurrency($totalItem, $currency)
                );
            }
            $html .= sprintf('<tr class="total"><th colspan="3">Total</th><td>%s</td></tr>', formatCurrency($total, $currency));
            $html .= '</table>';
            $html .= '</div>';
        }

        $html .= '</div>'; // End content

        // Footer (fixed at bottom, dynamic height)
        $html .= '<div class="footer">';
        $footerContent = renderWithVariables($template['footer_html'] ?? '<p style="margin: 0; font-size: 9px;">' . h($template['name'] ?? 'Proposal') . ' • ' . h($proposal['proposal_number'] ?? 'PRO-' . $proposal['id']) . '</p>', $templateVariables);
        $footerContent = processImagesForPdf($footerContent);
        $html .= $footerContent; // Don't force center - preserve TinyMCE alignment
        $html .= '</div>';

        // Page number - use CSS content
        $html .= '<div class="page-number"></div>';
        $html .= '</body></html>';

        // Generate real PDF using DomPDF
        $options = new Options();
        $options->set('defaultFont', 'Arial');
        $options->set('isRemoteEnabled', true);
        $options->set('isHtml5ParserEnabled', true);
        $options->set('isPhpEnabled', true);
        $options->set('defaultPaperSize', 'a4');
        $options->set('defaultPaperOrientation', 'portrait');
        $options->set('margin-top', '20mm');
        $options->set('margin-bottom', '20mm');
        $options->set('margin-left', '20mm');
        $options->set('margin-right', '20mm');
        
        $dompdf = new Dompdf($options);
        $dompdf->loadHtml($html);
        $dompdf->setPaper('A4', 'portrait');
        $dompdf->render();
        
        // Delete old PDF if it exists
        if (!empty($proposal['pdf_path'])) {
            // Extract company ID and filename from old path
            $oldPathParts = explode('/', $proposal['pdf_path']);
            if (count($oldPathParts) >= 3 && $oldPathParts[1] === 'companies' && is_numeric($oldPathParts[2])) {
                $oldCompanyId = (int) $oldPathParts[2];
                $oldFilename = end($oldPathParts);
                FileManager::deleteFile($oldCompanyId, 'pdfs', $oldFilename);
            } else {
                // Legacy path - delete from old location
                $oldPdfPath = __DIR__ . '/..' . $proposal['pdf_path'];
                if (file_exists($oldPdfPath)) {
                    unlink($oldPdfPath);
                }
            }
        }
        
        // Save PDF to company-specific storage
        $companyId = TenantDB::getTenant();
        $filename = 'proposal_' . $id . '_' . date('Y-m-d_H-i-s') . '.pdf';
        
        // Ensure company directories exist
        FileManager::ensureCompanyDirectories($companyId);
        
        // Save PDF file to company storage
        $fullPath = FileManager::getFilePath($companyId, 'proposals', $filename);
        file_put_contents($fullPath, $dompdf->output());
        
        // Update proposal with new PDF path
        $pdfPath = '/storage/companies/' . $companyId . '/proposals/' . $filename;
        self::update($id, ['pdf_path' => $pdfPath]);
        
        return $pdfPath;
    }
}
