<?php
// includes/bootstrap.php

require_once __DIR__ . '/../config.php';

// ── Database ──────────────────────────────────────────────────────────────────
function db(): PDO {
    static $pdo = null;
    if ($pdo === null) {
        $dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=" . DB_CHARSET;
        $opts = [
            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES   => false,
        ];
        $pdo = new PDO($dsn, DB_USER, DB_PASS, $opts);
    }
    return $pdo;
}

function query(string $sql, array $params = []): PDOStatement {
    $stmt = db()->prepare($sql);
    $stmt->execute($params);
    return $stmt;
}

function fetchOne(string $sql, array $params = []): ?array {
    return query($sql, $params)->fetch() ?: null;
}

function fetchAll(string $sql, array $params = []): array {
    return query($sql, $params)->fetchAll();
}

function insert(string $table, array $data): int {
    $cols   = implode(',', array_keys($data));
    $places = implode(',', array_fill(0, count($data), '?'));
    query("INSERT INTO $table ($cols) VALUES ($places)", array_values($data));
    return (int) db()->lastInsertId();
}

function update(string $table, array $data, string $where, array $whereParams = []): void {
    $set = implode(',', array_map(fn($k) => "$k=?", array_keys($data)));
    query("UPDATE $table SET $set WHERE $where", [...array_values($data), ...$whereParams]);
}

// ── Session / Auth ─────────────────────────────────────────────────────────────
if (session_status() === PHP_SESSION_NONE) {
    session_name('debrieft_session');
    session_start();
}

function auth(): ?array {
    return $_SESSION['user'] ?? null;
}

function requireAuth(): array {
    $user = auth();
    if (!$user) {
        header('Location: ' . APP_URL . '/login.php');
        exit;
    }
    return $user;
}

function login(array $user): void {
    session_regenerate_id(true);
    $_SESSION['user'] = $user;
}

function logout(): void {
    session_destroy();
    header('Location: ' . APP_URL . '/login.php');
    exit;
}

// ── CSRF ───────────────────────────────────────────────────────────────────────
function csrfToken(): string {
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

function verifyCsrf(): void {
    $token = $_POST['csrf_token'] ?? '';
    if (!hash_equals(csrfToken(), $token)) {
        http_response_code(403);
        die('Invalid CSRF token.');
    }
}

// ── Flash messages ─────────────────────────────────────────────────────────────
function flash(string $type, string $msg): void {
    $_SESSION['flash'][] = compact('type', 'msg');
}

function getFlash(): array {
    $f = $_SESSION['flash'] ?? [];
    unset($_SESSION['flash']);
    return $f;
}

// ── Helpers ────────────────────────────────────────────────────────────────────
function e(mixed $v): string { return htmlspecialchars((string)($v ?? ''), ENT_QUOTES, 'UTF-8'); }

function redirect(string $url): never {
    header("Location: $url");
    exit;
}

function slug(int $len = 12): string {
    return bin2hex(random_bytes($len));
}

function formatMoney(float $amount): string {
    return '$' . number_format($amount, 2);
}

function formatDate(string $date): string {
    return date('M j, Y', strtotime($date));
}

// ── AI Brief Generation ────────────────────────────────────────────────────────
// ── Unified AI caller — supports DeepSeek (free) and Anthropic ───────────────
function callAI(string $prompt, int $userId, int $maxTokens = 2000): array {
    // Returns ['ok' => bool, 'text' => string, 'provider' => string]
    $studio   = getStudioSettings($userId);
    $provider = $studio['ai_provider'] ?? 'deepseek';

    // Resolve key: studio setting → config constant → fallback other provider
    if ($provider === 'deepseek') {
        $apiKey = $studio['deepseek_api_key'] ?? '';
        if (!$apiKey) {
            // No DeepSeek key — try Anthropic as fallback
            $provider = 'anthropic';
            $apiKey   = ANTHROPIC_API_KEY;
        }
    } else {
        $apiKey = $studio['anthropic_api_key'] ?? '';
        if (!$apiKey) $apiKey = ANTHROPIC_API_KEY;
        if (!$apiKey) {
            // No Anthropic key — try DeepSeek as fallback
            $provider = 'deepseek';
            $apiKey   = $studio['deepseek_api_key'] ?? '';
        }
    }

    if (!$apiKey) {
        return ['ok' => false, 'text' => 'No AI API key configured. Add a DeepSeek key (free) or Anthropic key in Studio Admin → AI Settings.', 'provider' => $provider];
    }

    if ($provider === 'deepseek') {
        // DeepSeek — OpenAI-compatible endpoint
        $ch = curl_init('https://api.deepseek.com/chat/completions');
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_HTTPHEADER     => [
                'Content-Type: application/json',
                'Authorization: Bearer ' . $apiKey,
            ],
            CURLOPT_POSTFIELDS => json_encode([
                'model'       => 'deepseek-chat',
                'max_tokens'  => $maxTokens,
                'messages'    => [
                    ['role' => 'system', 'content' => 'You are an expert web design strategist. Always respond in clean markdown.'],
                    ['role' => 'user',   'content' => $prompt],
                ],
                'temperature' => 0.7,
            ]),
            CURLOPT_TIMEOUT => 90,
        ]);
        $response = curl_exec($ch);
        $err      = curl_error($ch);
        curl_close($ch);
        if ($err) return ['ok' => false, 'text' => 'DeepSeek cURL error: ' . $err, 'provider' => 'deepseek'];
        $data = json_decode($response, true);
        if (isset($data['error'])) return ['ok' => false, 'text' => 'DeepSeek error: ' . ($data['error']['message'] ?? 'Unknown'), 'provider' => 'deepseek'];
        $text = $data['choices'][0]['message']['content'] ?? '';
        return ['ok' => (bool)$text, 'text' => $text ?: 'DeepSeek returned empty response.', 'provider' => 'deepseek'];

    } else {
        // Anthropic
        $ch = curl_init('https://api.anthropic.com/v1/messages');
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_HTTPHEADER     => [
                'Content-Type: application/json',
                'x-api-key: ' . $apiKey,
                'anthropic-version: 2023-06-01',
            ],
            CURLOPT_POSTFIELDS => json_encode([
                'model'      => ANTHROPIC_MODEL,
                'max_tokens' => $maxTokens,
                'messages'   => [['role' => 'user', 'content' => $prompt]],
            ]),
            CURLOPT_TIMEOUT => 90,
        ]);
        $response = curl_exec($ch);
        $err      = curl_error($ch);
        curl_close($ch);
        if ($err) return ['ok' => false, 'text' => 'Anthropic cURL error: ' . $err, 'provider' => 'anthropic'];
        $data = json_decode($response, true);
        if (isset($data['error'])) return ['ok' => false, 'text' => 'Anthropic error: ' . ($data['error']['message'] ?? 'Unknown'), 'provider' => 'anthropic'];
        $text = $data['content'][0]['text'] ?? '';
        return ['ok' => (bool)$text, 'text' => $text ?: 'Anthropic returned empty response.', 'provider' => 'anthropic'];
    }
}

// ── Generate project brief ─────────────────────────────────────────────────────
function generateBriefWithAI(array $intake, array $user): string {
    $prompt = <<<PROMPT
You are an expert web design strategist. Based on the following client intake data, write a comprehensive professional project brief for a web designer.

**Client Intake:**
- Business Name: {$intake['business_name']}
- Industry: {$intake['industry']}
- Project Type: {$intake['project_type']}
- Goals: {$intake['goals']}
- Target Audience: {$intake['target_audience']}
- Competitors: {$intake['competitors']}
- Design Style: {$intake['design_style']}
- Color Preferences: {$intake['color_preferences']}
- Features Needed: {$intake['features_needed']}
- Budget Range: {$intake['budget_range']}
- Timeline: {$intake['timeline']}
- Additional Notes: {$intake['additional_notes']}

Generate a structured brief with these sections:
1. **Executive Summary**
2. **Project Objectives**
3. **Target Audience**
4. **Scope of Work**
5. **Design Direction**
6. **Key Features & Functionality**
7. **Technical Recommendations**
8. **Timeline & Milestones**
9. **Success Metrics**

Use professional language. Format in clean markdown.
PROMPT;

    $result = callAI($prompt, $user['id'], 2000);
    return $result['text'];
}

// ── Generate Website Specification with AI ────────────────────────────────────
function generateWebsiteSpecWithAI(array $spec, int $userId): string {
    $pages    = json_decode($spec['pages']    ?? '[]', true) ?: [];
    $services = json_decode($spec['services'] ?? '[]', true) ?: [];

    $pageList    = implode(', ', array_column($pages,    'name'));
    $serviceList = implode(', ', array_column($services, 'name'));

    $prompt = <<<PROMPT
You are a senior web design consultant. Create a detailed, professional website specification document based on the client data below.

**Client Details:**
- Business: {$spec['business_name']}
- Industry: {$spec['industry']}
- Tagline: {$spec['tagline']}
- About: {$spec['about']}
- Website URL: {$spec['website_url']}

**Pages Required:** {$pageList}
**Services:** {$serviceList}

**Business Context:**
- Target Audience: {$spec['target_audience']}
- Competitors: {$spec['competitors']}
- Goals: {$spec['goals']}
- Unique Selling Proposition: {$spec['usp']}

**Brand & Design:**
- Brand Style: {$spec['brand_style']}
- Brand Personality: {$spec['brand_personality']}
- Heading Font: {$spec['heading_font']}
- Body Font: {$spec['body_font']}
- Color Mood: {$spec['color_mood']}
- Color Notes: {$spec['color_notes']}

Write a complete website specification document with these sections:

## 1. Project Overview
Compelling summary of the project, client, and objectives.

## 2. Brand Identity
Brand voice, personality traits, tone of communication, and positioning.

## 3. Target Audience & User Personas
2 detailed user personas with demographics, goals, pain points.

## 4. Sitemap & Page Descriptions
Each page with its purpose, key content, and calls to action.

## 5. Services Showcase
How each service should be presented and what makes it compelling.

## 6. Design System Guidelines
Typography hierarchy, spacing principles, UI component recommendations based on the chosen style.

## 7. Content Strategy
What content each page needs, SEO considerations, copywriting tone.

## 8. Technical Requirements
Recommended platform (WordPress, custom, etc.), essential plugins/features, performance targets.

## 9. Success Metrics & KPIs
How to measure the website's effectiveness post-launch.

Use professional language. Be specific and actionable. Format in clean markdown.
PROMPT;

    $result = callAI($prompt, $userId, 3000);
    return $result['text'];
}

// ── Markdown to HTML (simple) ─────────────────────────────────────────────────
function markdownToHtml(string $md): string {
    $lines  = explode("\n", $md);
    $out    = [];
    $inUl   = false;
    $inOl   = false;
    $para   = [];

    $flushPara = function() use (&$para, &$out) {
        if ($para) {
            $text = implode(' ', $para);
            if ($text !== '') $out[] = '<p>' . $text . '</p>';
            $para = [];
        }
    };

    foreach ($lines as $line) {
        // Headings
        if (preg_match('/^### (.+)$/', $line, $m)) {
            $flushPara();
            if ($inUl) { $out[] = '</ul>'; $inUl = false; }
            if ($inOl) { $out[] = '</ol>'; $inOl = false; }
            $out[] = '<h3>' . $m[1] . '</h3>';
        } elseif (preg_match('/^## (.+)$/', $line, $m)) {
            $flushPara();
            if ($inUl) { $out[] = '</ul>'; $inUl = false; }
            if ($inOl) { $out[] = '</ol>'; $inOl = false; }
            $out[] = '<h2>' . $m[1] . '</h2>';
        } elseif (preg_match('/^# (.+)$/', $line, $m)) {
            $flushPara();
            if ($inUl) { $out[] = '</ul>'; $inUl = false; }
            if ($inOl) { $out[] = '</ol>'; $inOl = false; }
            $out[] = '<h1>' . $m[1] . '</h1>';
        // Numbered list items
        } elseif (preg_match('/^\d+\.\s+(.+)$/', $line, $m)) {
            $flushPara();
            if ($inUl) { $out[] = '</ul>'; $inUl = false; }
            if (!$inOl) { $out[] = '<ol>'; $inOl = true; }
            $out[] = '<li>' . $m[1] . '</li>';
        // Bullet list items
        } elseif (preg_match('/^[-*] (.+)$/', $line, $m)) {
            $flushPara();
            if ($inOl) { $out[] = '</ol>'; $inOl = false; }
            if (!$inUl) { $out[] = '<ul>'; $inUl = true; }
            $out[] = '<li>' . $m[1] . '</li>';
        // Blank line — flush paragraph / close list
        } elseif (trim($line) === '') {
            if ($inUl) { $out[] = '</ul>'; $inUl = false; }
            if ($inOl) { $out[] = '</ol>'; $inOl = false; }
            $flushPara();
        // Plain text line — accumulate into paragraph
        } else {
            if ($inUl) { $out[] = '</ul>'; $inUl = false; }
            if ($inOl) { $out[] = '</ol>'; $inOl = false; }
            $para[] = $line;
        }
    }

    if ($inUl) $out[] = '</ul>';
    if ($inOl) $out[] = '</ol>';
    $flushPara();

    $html = implode("\n", $out);
    // Inline bold
    $html = preg_replace('/\*\*(.+?)\*\*/', '<strong>$1</strong>', $html);
    return $html;
}

// ── Status badge ──────────────────────────────────────────────────────────────
function statusBadge(string $status): string {
    $map = [
        'intake'    => 'badge-purple',
        'brief'     => 'badge-blue',
        'quote'     => 'badge-yellow',
        'contract'  => 'badge-orange',
        'active'    => 'badge-green',
        'handover'  => 'badge-teal',
        'completed' => 'badge-gray',
        'draft'     => 'badge-gray',
        'sent'      => 'badge-blue',
        'accepted'  => 'badge-green',
        'declined'  => 'badge-red',
        'signed'    => 'badge-green',
    ];
    $cls = $map[$status] ?? 'badge-gray';
    return "<span class=\"badge $cls\">" . ucfirst(e($status)) . "</span>";
}

// ── Project helper ─────────────────────────────────────────────────────────────
function getProject(int $id, int $userId): ?array {
    return fetchOne(
        "SELECT p.*, c.name AS client_name, c.email AS client_email, c.company AS client_company
         FROM projects p JOIN clients c ON c.id = p.client_id
         WHERE p.id = ? AND p.user_id = ?",
        [$id, $userId]
    );
}

// ── Studio Settings ───────────────────────────────────────────────────────────
function getStudioSettings(int $userId): array {
    static $cache = [];
    if (isset($cache[$userId])) return $cache[$userId];
    $defaults = [
        'studio_name'         => '',
        'owner_name'          => '',
        'address'             => '',
        'tax_id'              => '',
        'phone'               => '',
        'email'               => '',
        'website'             => '',
        'logo_url'            => '',
        'accent_color'        => '#5b5ef4',
        'bank_details'        => '',
        'invoice_prefix'      => 'INV',
        'invoice_next_number' => 1,
        'default_currency'    => 'USD',
        'payment_due_days'    => 30,
        'invoice_footer'      => 'Thank you for your business!',
        'smtp_host'           => '',
        'smtp_port'           => 587,
        'smtp_user'           => '',
        'smtp_pass'           => '',
        'smtp_from_name'      => '',
        'smtp_encryption'     => 'tls',
        'ai_provider'         => 'deepseek',
        'deepseek_api_key'    => '',
        'anthropic_api_key'   => '',
    ];
    $row = fetchOne("SELECT * FROM studio_settings WHERE user_id = ?", [$userId]);
    $cache[$userId] = $row
        ? array_merge($defaults, array_filter($row, fn($v) => $v !== null && $v !== ''))
        : $defaults;
    return $cache[$userId];
}

function saveStudioSettings(int $userId, array $data): void {
    $exists = fetchOne("SELECT id FROM studio_settings WHERE user_id = ?", [$userId]);
    if ($exists) {
        update('studio_settings', $data, 'user_id = ?', [$userId]);
    } else {
        insert('studio_settings', array_merge(['user_id' => $userId], $data));
    }
}

function requireAdmin(): array {
    $user = requireAuth();
    if (($user['role'] ?? '') !== 'admin') {
        flash('error', 'Admin access required.');
        redirect(APP_URL . '/dashboard.php');
    }
    return $user;
}

// ── Currency helpers ──────────────────────────────────────────────────────────
function currencySymbol(string $currency): string {
    return match($currency) { 'EUR' => '€', 'GBP' => '£', default => '$' };
}

function formatCurrency(float $amount, string $currency = 'USD'): string {
    return currencySymbol($currency) . number_format($amount, 2);
}

// ── Invoice number helpers ────────────────────────────────────────────────────
function nextInvoiceNumber(int $userId): string {
    $s = fetchOne("SELECT invoice_prefix, invoice_next_number FROM studio_settings WHERE user_id = ?", [$userId]);
    $prefix = $s['invoice_prefix'] ?? 'INV';
    $num    = (int)($s['invoice_next_number'] ?? 1);
    return $prefix . '-' . str_pad($num, 4, '0', STR_PAD_LEFT);
}

function incrementInvoiceNumber(int $userId): void {
    $exists = fetchOne("SELECT id FROM studio_settings WHERE user_id = ?", [$userId]);
    if ($exists) {
        query("UPDATE studio_settings SET invoice_next_number = invoice_next_number + 1 WHERE user_id = ?", [$userId]);
    }
}

// ── Fetch logo as base64 data URI ─────────────────────────────────────────────
function fetchLogoBase64(string $url): ?string {
    if (!$url || !extension_loaded('curl')) return null;
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 8,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_USERAGENT      => 'Debrieft/1.0',
    ]);
    $data        = curl_exec($ch);
    $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
    $err         = curl_error($ch);
    curl_close($ch);
    if ($err || !$data) return null;
    $type = strtolower(explode(';', $contentType)[0]);
    $allowed = ['image/png','image/jpeg','image/jpg','image/webp','image/gif','image/svg+xml'];
    if (!in_array($type, $allowed)) return null;
    return 'data:' . $type . ';base64,' . base64_encode($data);
}

// ── Send invoice email via PHPMailer or fallback ──────────────────────────────
function sendInvoiceEmail(array $invoice, array $client, array $user, array $studio, string $pdfContent, string $filename): bool {
    $vendorPath = __DIR__ . '/../vendor/autoload.php';
    if (!file_exists($vendorPath)) return false;
    require_once $vendorPath;
    $mail = new \PHPMailer\PHPMailer\PHPMailer(true);
    try {
        if ($studio['smtp_host']) {
            $mail->isSMTP();
            $mail->Host       = $studio['smtp_host'];
            $mail->SMTPAuth   = (bool)$studio['smtp_user'];
            $mail->Username   = $studio['smtp_user'];
            $mail->Password   = $studio['smtp_pass'];
            $mail->Port       = (int)($studio['smtp_port'] ?: 587);
            $mail->SMTPSecure = match($studio['smtp_encryption']) {
                'ssl'  => \PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_SMTPS,
                'none' => '',
                default => \PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS,
            };
        } else {
            $mail->isMail();
        }
        $fromName  = $studio['smtp_from_name'] ?: ($studio['studio_name'] ?: $user['name']);
        $fromEmail = $studio['smtp_user'] ?: $user['email'];
        $mail->setFrom($fromEmail, $fromName);
        $mail->addAddress($client['email'], $client['name']);
        $mail->addReplyTo($user['email'], $user['name']);
        $mail->Subject = 'Invoice ' . $invoice['invoice_number'] . ' from ' . $fromName;
        $mail->isHTML(true);
        $mail->Body = '<p>Dear ' . htmlspecialchars($client['name']) . ',</p>'
            . '<p>Please find your invoice <strong>' . htmlspecialchars($invoice['invoice_number']) . '</strong> attached.</p>'
            . ($invoice['due_date'] ? '<p>Payment is due by <strong>' . date('d M Y', strtotime($invoice['due_date'])) . '</strong>.</p>' : '')
            . '<p>' . nl2br(htmlspecialchars($studio['bank_details'] ?? '')) . '</p>'
            . '<p>If you have any questions, please don\'t hesitate to reach out.</p>'
            . '<p>Kind regards,<br>' . htmlspecialchars($fromName) . '</p>';
        $mail->AltBody = strip_tags($mail->Body);
        $mail->addStringAttachment($pdfContent, $filename, 'base64', 'application/pdf');
        $mail->send();
        return true;
    } catch (\Exception $e) {
        error_log('Invoice email error: ' . $e->getMessage());
        return false;
    }
}
