<?php declare(strict_types=1);

ini_set('display_errors', '0');
ini_set('log_errors', '1');
error_reporting(E_ALL);
/**
 * Planning Report Generator (MVP)
 * Input:  JSON payload (see schema below)
 * Output: { ok: true, markdown: "...", html: "...", meta: {...} }
 *
 * Place at: /internal/classes/generate_planning_report.php
 * Test:     curl -s -X POST -H "Content-Type: application/json" \
 *           --data @sample.json http://localhost/internal/classes/generate_planning_report.php | jq
 */
date_default_timezone_set('Australia/Hobart');

$allowedOrigins = [
    'http://192.168.8.69:2380',   // your demo.html origin
    'http://localhost',           // handy for local dev
    'http://localhost:8080',
    'https://modulosdesign.com.au',
	'https://llm.modulos.com.au'
];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if ($origin && in_array($origin, $allowedOrigins, true)) {
    header("Access-Control-Allow-Origin: $origin");
    header("Vary: Origin"); // prevent cache mixups
}
// If you need credentials/cookies later, also set:
// header('Access-Control-Allow-Credentials: true');

header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Accept, X-Requested-With');

// Preflight short-circuit
if (($_SERVER['REQUEST_METHOD'] ?? '') === 'OPTIONS') {
    http_response_code(204);
    exit; // stop here, no body required
}




header('Content-Type: application/json; charset=UTF-8');

try {
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        http_response_code(405);
        echo json_encode(['ok' => false, 'error' => 'Use POST with application/json']);
        exit;
    }

    $raw = file_get_contents('php://input') ?: '';
    $in  = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);

    // --------- Schema (minimum viable) ----------
    $d = [
        // site
        'address'           => trim((string)($in['address'] ?? '')),
        'lat'               => floatval($in['lat'] ?? 0),
        'lng'               => floatval($in['lng'] ?? 0),
        'pid'               => trim((string)($in['pid'] ?? '')),
        'title_id'          => trim((string)($in['title_id'] ?? '')),
        'total_area'        => $in['total_area'] ?? null, // e.g. {sqm_label:"1,652 m²", ha_label:"0.1652 ha"} or string
        'area_sqm'          => $in['area_sqm'] ?? '',
        'area_ha'           => $in['area_ha'] ?? '',
        'tenure'            => trim((string)($in['tenure'] ?? '')),
        'lpi'               => trim((string)($in['lpi'] ?? '')),
        'list_guid'         => trim((string)($in['list_guid'] ?? '')),
        'locality'          => trim((string)($in['locality'] ?? '')),
        'council'           => trim((string)($in['council'] ?? '')),
        'planning_scheme'   => trim((string)($in['planning_scheme'] ?? 'Tasmanian Planning Scheme')),
        'planning_zones'    => array_values(array_filter((array)($in['planning_zones'] ?? []))),
        'planning_codes'    => array_values(array_filter((array)($in['planning_codes'] ?? []))),

        // proposal
        'use_class'         => trim((string)($in['use_class'] ?? 'Educational and Occasional Care')),
        'proposal_summary'  => trim((string)($in['proposal_summary'] ?? '')), // 1–3 paras freeform
        'operations'        => (array)($in['operations'] ?? []),             // ['hours','staff','children']
        'parking'           => (array)($in['parking'] ?? []),                // ['cars','bikes','accessible','motorcycle']
        'signage'           => (array)($in['signage'] ?? []),                // [{type,desc}, ...]
        'consultants'       => (array)($in['consultants'] ?? []),            // ['TIA'=>'…','Acoustic'=>'…','Bushfire'=>'…']

        // overlays
        'overlays'          => (array)($in['overlays'] ?? []),               // ['bushfire'=>bool, 'airport_noise'=>bool, ...]

        // assessments matrix (zone + codes)
        'standards'         => (array)($in['standards'] ?? []),              // [{clause, standard, acceptable, relies_on_pc:[], notes}]

        // assets (optional)
        'map_png'           => (string)($in['map_png'] ?? ''),               // data:image/png;base64,...
        'appendices'        => array_values(array_filter((array)($in['appendices'] ?? []))),

        // meta
        'prepared_for'      => trim((string)($in['prepared_for'] ?? '')),
        'prepared_by'       => trim((string)($in['prepared_by'] ?? 'Modulos Design')),
        'author'            => trim((string)($in['author'] ?? '')),
        'job_number'        => trim((string)($in['job_number'] ?? '')),
        'version'           => trim((string)($in['version'] ?? 'Draft')),
        'prepared_date'     => trim((string)($in['prepared_date'] ?? date('j F Y'))),
        'acknowledgement'   => (string)($in['acknowledgement'] ?? "We acknowledge the palawa people as the Traditional Owners of lutruwita/Tasmania and pay our respects to Elders past and present."),
    ];

    // Minimal required fields
    foreach (['address','planning_scheme'] as $k) {
        if ($d[$k] === '' || $d[$k] === null) {
            throw new RuntimeException("Missing required field: {$k}");
        }
    }

    // Helpers -----------------------------------------------------------
    $join = fn(array $arr, string $sep=', ') => implode($sep, array_values(array_filter($arr, fn($x)=>$x!=='' && $x!==null)));

    $fmt_area = function($d) {
        if (is_array($d['total_area'] ?? null)) {
            return $d['total_area']['ha_label'] ?? $d['total_area']['sqm_label'] ?? '';
        }
        return $d['area_ha'] ?: $d['area_sqm'];
    };

    $md_table_row = fn(array $cols) => '| ' . implode(' | ', array_map(fn($c)=>trim((string)$c) ?: '–', $cols)) . ' |';

    $render_standards = function(array $rows) use ($md_table_row) {
        if (!$rows) return "_No specific standards provided in this draft._\n";
        $out   = [];
        $out[] = $md_table_row(['Clause','Standard','AS','PC','Notes']);
        $out[] = $md_table_row(['---','---','---','---','---']);
        foreach ($rows as $r) {
            $out[] = $md_table_row([
                $r['clause']      ?? '',
                $r['standard']    ?? '',
                $r['acceptable']  ?? '',
                $r['relies_on_pc'] ? implode(', ', (array)$r['relies_on_pc']) : '',
                $r['notes']       ?? ''
            ]);
        }
        return implode("\n", $out)."\n";
    };

    // Markdown builder --------------------------------------------------
    $md = [];
    $md[] = '# Supporting Planning Report';
    $md[] = '';
    $md[] = "Prepared for: **" . ($d['prepared_for'] ?: '—') . "**";
    $md[] = "Prepared by: **" . ($d['prepared_by'] ?: '—') . "**" . ($d['author'] ? " ({$d['author']})" : "");
    $md[] = "Job No.: **" . ($d['job_number'] ?: '—') . "**";
    $md[] = "Version: **" . ($d['version'] ?: '—') . "**";
    $md[] = "Date: **" . ($d['prepared_date'] ?: '—') . "**";
    $md[] = '';
    $md[] = '> ' . $d['acknowledgement'];
    $md[] = '';

    // Permit overview
    $md[] = '## Permit overview';
    $md[] = '### Permit application details';
    $md[] = $md_table_row(['Applicant','Owner','Address','Title']);
    $md[] = $md_table_row(['---','---','---','---']);
    $md[] = $md_table_row([
        $d['prepared_for'] ?: '—',
        '—',
        $d['address'],
        ($d['title_id'] ?: '—')
    ]);
    $md[] = '';
    $md[] = '### Relevant Planning Provisions';
    $md[] = "- Applicable planning scheme: **{$d['planning_scheme']}**";
    if ($d['planning_zones']) $md[] = '- Zone(s): **' . $join($d['planning_zones']) . '**';
    if ($d['planning_codes']) $md[] = '- Codes: **' . $join($d['planning_codes']) . '**';
    $md[] = '';

    // Proposal
    $md[] = '## 1. Introduction';
    $md[] = '**Purpose of the report.** This report seeks planning approval for the proposed use and development described below and assesses the application against the relevant provisions of the Tasmanian Planning Scheme.';
    $md[] = '';
    $md[] = '## 2. Proposal';
    if ($d['proposal_summary']) $md[] = $d['proposal_summary'];
    $ops = [];
    if (!empty($d['operations']['hours'])) $ops[] = "**Hours:** {$d['operations']['hours']}";
    if (!empty($d['operations']['staff'])) $ops[] = "**Staff:** {$d['operations']['staff']}";
    if (!empty($d['operations']['children'])) $ops[] = "**Children capacity:** {$d['operations']['children']}";
    if ($ops) $md[] = implode('  \n', $ops);
    if ($d['parking']) {
        $pbits = [];
        if (isset($d['parking']['cars'])) $pbits[] = "{$d['parking']['cars']} car spaces";
        if (isset($d['parking']['accessible'])) $pbits[] = "{$d['parking']['accessible']} accessible";
        if (isset($d['parking']['bikes'])) $pbits[] = "{$d['parking']['bikes']} bicycle spaces";
        if (isset($d['parking']['motorcycle'])) $pbits[] = "{$d['parking']['motorcycle']} motorcycle spaces";
        if ($pbits) $md[] = '**Parking:** ' . implode(', ', $pbits) . '.';
    }
    if ($d['signage']) {
        $md[] = '**Signage:**';
        foreach ($d['signage'] as $s) {
            $md[] = "- " . trim(is_array($s) ? (($s['type'] ?? 'Sign') . ': ' . ($s['desc'] ?? '')) : (string)$s);
        }
    }
    if (!empty($d['map_png'])) {
        $md[] = '';
        $md[] = '![Site and surrounds map]('.$d['map_png'].')';
        $md[] = '_Figure: Site context (auto-captured from map)._';
    }
    $md[] = '';

    // Site
    $md[] = '## 3. Site description';
    $md[] = $md_table_row(['Property ID','Title ID','Locality','Area','Tenure','LIST GUID']);
    $md[] = $md_table_row(['---','---','---','---','---','---']);
    $md[] = $md_table_row([
        $d['pid'] ?: '—',
        $d['title_id'] ?: '—',
        $d['locality'] ?: '—',
        $fmt_area($d) ?: '—',
        $d['tenure'] ?: '—',
        $d['list_guid'] ?: '—'
    ]);
    $md[] = '';

    // Zoning
    $md[] = '## 4. Zoning assessment';
    $md[] = "**Zone:** " . ($d['planning_zones'] ? $join($d['planning_zones']) : '—');
    $md[] = "**Use class:** {$d['use_class']} (assessment against applicable use and development standards).";
    $md[] = '';

    // Standards matrix
    $md[] = '### 4.x Applicable standards (zone + codes overview)';
    $md[] = $render_standards($d['standards']);

    // Codes — notes (driven by the standards rows)
    $md[] = '## 5. Code assessment';
    if (in_array('Signs', $d['planning_codes']))                         $md[] = '- **Signs Code** – see relevant rows above.';
    if (in_array('Parking and Sustainable Transport', $d['planning_codes'])) $md[] = '- **Parking and Sustainable Transport Code** – see relevant rows above.';
    if (in_array('Road and Railway Assets', $d['planning_codes']))       $md[] = '- **Road and Railway Assets Code** – see relevant rows above.';
    if (!empty($d['overlays']['bushfire']))                              $md[] = '- **Bushfire-Prone Areas Code** – see relevant rows above.';
    if (!empty($d['overlays']['airport_noise']))                         $md[] = '- **Safeguarding of Airports Code** – see relevant rows above.';
    $md[] = '';

    // Consultants
    if ($d['consultants']) {
        $md[] = '### Supporting technical reports';
        foreach ($d['consultants'] as $k => $v) {
            $md[] = "- **{$k}:** {$v}";
        }
        $md[] = '';
    }

    // Conclusion (quick tally)
    $t_as = 0; $t_pc = 0;
    foreach ($d['standards'] as $r) {
        if (!empty($r['acceptable'])) $t_as++;
        if (!empty($r['relies_on_pc'])) $t_pc++;
    }
    $md[] = '## 6. Conclusion';
    $md[] = "This application has been assessed against the Tasmanian Planning Scheme provisions relevant to the site and proposal. Based on the information provided and the supporting technical assessments, the proposal **complies with acceptable solutions for ~{$t_as} standards** and **relies on performance criteria for ~{$t_pc} standards**. Approval is therefore requested subject to any reasonable conditions.";
    $md[] = '';

    // Appendices (labels only)
    if ($d['appendices']) {
        $md[] = '## Appendices';
        foreach ($d['appendices'] as $i => $label) {
            $md[] = ($i+1) . ". " . trim((string)$label);
        }
        $md[] = '';
    }

    $markdown = implode("\n", $md);

    // Minimal Markdown → HTML
    $html = md_to_html_min($markdown);

    // Optional: save a .md copy (ensure directory exists & is writable)
    $SAVE_DIR = __DIR__ . '/../../reports';
    if (is_dir($SAVE_DIR) && is_writable($SAVE_DIR)) {
        $fname = sanitize_filename("Planning Report - {$d['address']} - " . date('Ymd_His')) . ".md";
        @file_put_contents($SAVE_DIR . '/' . $fname, $markdown);
    }

    echo json_encode([
        'ok'       => true,
        'markdown' => $markdown,
        'html'     => $html,
        'meta'     => [
            'address' => $d['address'],
            'scheme'  => $d['planning_scheme'],
            'zones'   => $d['planning_zones'],
            'codes'   => $d['planning_codes'],
        ],
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;

} catch (Throwable $e) {
    http_response_code(400);
    echo json_encode(['ok' => false, 'error' => $e->getMessage()]);
    exit;
}

/** -------- Helpers -------- */

function sanitize_filename(string $s): string {
    $s = preg_replace('~[^\w\-. ]+~u', '', $s);
    $s = preg_replace('~\s+~', ' ', $s);
    return trim($s) ?: 'report';
}

function esc_html(string $s): string {
    return htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

function md_to_html_min(string $md): string {
    // Extremely small converter: headers, bold/italics, lists, images, tables, paragraphs.
    $h = esc_html($md);

    // Images ![alt](src)
    $h = preg_replace('~!\[([^\]]*)\]\(([^)]+)\)~', '<img alt="$1" src="$2" style="max-width:100%;height:auto;border-radius:8px;" />', $h);

    // Bold / italic
    $h = preg_replace('~\*\*([^*]+)\*\*~', '<strong>$1</strong>', $h);
    $h = preg_replace('~\*([^*]+)\*~', '<em>$1</em>', $h);

    // Headers
    foreach ([6,5,4,3,2,1] as $n) {
        $re = '~^' . str_repeat('#', $n) . '\s*(.+)$~m';
        $h  = preg_replace($re, "<h{$n}>$1</h{$n}>", $h);
    }

    // Tables (GitHub-style)
    if (preg_match('~^\|.+\|$~m', $h)) {
        $lines = explode("\n", $h);
        $out = [];
        $inTable = false;
        foreach ($lines as $line) {
            if (preg_match('~^\|(.+)\|$~', $line)) {
                if (!$inTable) { $out[] = '<table class="table table-sm"><tbody>'; $inTable = true; }
                if (preg_match('~^\|\s*-+(\s*\|\s*-+)+\s*\|$~', $line)) continue; // separator
                $cells = array_map('trim', explode('|', trim($line, '|')));
                $out[] = '<tr>' . implode('', array_map(fn($c)=>'<td>'.esc_html($c ?: '–').'</td>', $cells)) . '</tr>';
            } else {
                if ($inTable) { $out[] = '</tbody></table>'; $inTable = false; }
                $out[] = $line;
            }
        }
        if ($inTable) $out[] = '</tbody></table>';
        $h = implode("\n", $out);
    }

    // Lists
    $h = preg_replace_callback('~(?:^|\n)([-*]\s.+(?:\n[-*]\s.+)*)~m', function($m){
        $items = preg_split('~\n~', trim($m[1]));
        $lis = '';
        foreach ($items as $li) {
            $txt = preg_replace('~^[-*]\s~', '', $li);
            $lis .= '<li>'. $txt .'</li>';
        }
        return "\n<ul>{$lis}</ul>";
    }, $h);

    // Line breaks "  \n" → <br>
    $h = str_replace("  \n", "<br>\n", $h);

    // Paragraphs
    $parts = preg_split('~\n{2,}~', $h);
    foreach ($parts as &$p) {
        if (!preg_match('~^\s*<(h\d|ul|ol|table|img|blockquote)~', $p)) {
            $p = '<p>'.$p.'</p>';
        }
    }
    $h = implode("\n", $parts);

    return '<article class="report-body" style="max-width:900px;margin:0 auto;">'.$h.'</article>';
}
