<?php

use App\Controllers\PublicController;

/**
 * Structured editing of projects for the admin console (galleries, Instagram,
 * cover). Content lives in cja_projects; the static site reads it at build
 * time, so a save is followed by a rebuild (the console's /devconsole/rebuild).
 *
 *   GET  /api/adminprojects/list             -> [{slug,title,galleryCount,...}]
 *   GET  /api/adminprojects/get?slug=...     -> full editable record
 *   POST /api/adminprojects/save             -> { slug, gallery, links, cover_image }
 *
 * All admin-gated. Only media-related fields are writable here; the freeform
 * agent console handles prose and layout.
 */
class AdminProjects extends PublicController
{
    public function list(): void
    {
        $this->requireAdmin();
        $rows = \Db::select('SELECT slug, title, status, gallery, links
                             FROM cja_projects ORDER BY sort_order ASC');
        $out = array_map(function ($r) {
            $gallery = json_decode($r['gallery'] ?? '[]', true) ?: [];
            $links = json_decode($r['links'] ?? '{}', true) ?: [];
            $filled = count(array_filter($gallery, fn($g) => !empty($g['src'])));
            return [
                'slug'       => $r['slug'],
                'title'      => $r['title'],
                'status'     => $r['status'],
                'gallery'    => count($gallery),
                'galleryFilled' => $filled,
                'hasInstagram'  => !empty($links['instagram']),
            ];
        }, $rows);
        $this->json(['projects' => $out]);
    }

    public function get(): void
    {
        $this->requireAdmin();
        $slug = (string) ($_GET['slug'] ?? '');
        $r = \Db::getRow('SELECT * FROM cja_projects WHERE slug = ?', [$slug]);
        if (!$r) {
            $this->json(null, 404, ['code' => 'not_found', 'message' => 'No such project.']);
        }
        $this->json([
            'slug'       => $r['slug'],
            'title'      => $r['title'],
            'kind'       => $r['kind'] ?? '',
            'period'     => $r['period_label'] ?? '',
            'status'     => $r['status'] ?? 'building',
            'summary'    => $r['summary'] ?? '',
            'lede'       => $r['lede'] ?? '',
            'body'       => $r['body'] ?? '',
            'role'       => $r['role'] ?? '',
            'cover'      => $r['cover_image'] ?? '',
            'categories' => json_decode($r['categories'] ?? '[]', true) ?: [],
            'stack'      => json_decode($r['stack'] ?? '[]', true) ?: [],
            'skills'     => json_decode($r['skills'] ?? '[]', true) ?: [],
            'metrics'    => json_decode($r['metrics'] ?? '[]', true) ?: [],
            'gallery'    => json_decode($r['gallery'] ?? '[]', true) ?: [],
            'links'      => json_decode($r['links'] ?? '{}', true) ?: [],
        ]);
    }

    /** Create a blank project from a title and return its slug. */
    public function create(): void
    {
        $this->requireAdmin();
        $this->guardPublic('adminprojects_create', 30, 300);

        $in = json_decode((string) file_get_contents('php://input'), true) ?: [];
        $title = mb_substr(trim((string) ($in['title'] ?? '')), 0, 160);
        if ($title === '') {
            $this->json(null, 400, ['code' => 'no_title', 'message' => 'Give the project a title.']);
        }

        // unique slug from the title
        $base = $this->slugify($title);
        $slug = $base;
        $n = 2;
        while (\Db::getValue('SELECT project_id FROM cja_projects WHERE slug = ?', [$slug])) {
            $slug = "{$base}-{$n}";
            $n++;
        }

        $order = (int) \Db::getValue('SELECT COALESCE(MAX(sort_order), 0) + 10 FROM cja_projects');
        \Db::insert('cja_projects', [
            'slug'         => $slug,
            'title'        => $title,
            'kind'         => '',
            'period_label' => 'In development',
            'status'       => 'building',
            'summary'      => '',
            'categories'   => '[]',
            'stack'        => '[]',
            'gallery'      => '[]',
            'links'        => '{}',
            'published'    => 1,
            'published_at' => date('Y-m-d H:i:s'),
            'sort_order'   => $order,
        ]);

        $this->json(['ok' => true, 'slug' => $slug]);
    }

    private function slugify(string $s): string
    {
        $s = strtolower(trim($s));
        $s = preg_replace('/[^a-z0-9]+/', '-', $s);
        $s = trim($s, '-');
        return $s !== '' ? mb_substr($s, 0, 100) : 'project';
    }

    public function save(): void
    {
        $this->requireAdmin();
        $this->guardPublic('adminprojects_save', 60, 300);

        $in = json_decode((string) file_get_contents('php://input'), true) ?: [];
        $slug = (string) ($in['slug'] ?? '');

        $id = \Db::getValue('SELECT project_id FROM cja_projects WHERE slug = ?', [$slug]);
        if (!$id) {
            $this->json(null, 404, ['code' => 'not_found', 'message' => 'No such project.']);
        }

        // ---- gallery: array of {src, alt, caption} -------------------------
        $gallery = [];
        foreach ((array) ($in['gallery'] ?? []) as $g) {
            $src = $this->safeMedia((string) ($g['src'] ?? ''));
            $gallery[] = [
                'src'     => $src,
                'alt'     => mb_substr(trim((string) ($g['alt'] ?? '')), 0, 200),
                'caption' => mb_substr(trim((string) ($g['caption'] ?? '')), 0, 120),
            ];
        }

        // ---- links: only known keys, only real URLs ------------------------
        $links = [];
        foreach (['live', 'instagram', 'github'] as $k) {
            $v = trim((string) ($in['links'][$k] ?? ''));
            if ($v !== '' && filter_var($v, FILTER_VALIDATE_URL)) {
                $links[$k] = $v;
            }
        }

        $cover = $this->safeMedia((string) ($in['cover_image'] ?? ''));

        // ---- text/content fields --------------------------------------------
        $title = mb_substr(trim((string) ($in['title'] ?? '')), 0, 160);
        $fields = [
            'gallery'     => json_encode($gallery, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
            'links'       => json_encode($links, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
            'cover_image' => $cover,
        ];
        if ($title !== '') $fields['title'] = $title;
        if (isset($in['kind']))    $fields['kind']         = mb_substr(trim((string) $in['kind']), 0, 60);
        if (isset($in['period']))  $fields['period_label'] = mb_substr(trim((string) $in['period']), 0, 60);
        if (isset($in['summary'])) $fields['summary']      = mb_substr(trim((string) $in['summary']), 0, 500);
        if (isset($in['lede']))    $fields['lede']         = mb_substr(trim((string) $in['lede']), 0, 1000);
        if (isset($in['body']))    $fields['body']         = (string) $in['body'];
        if (isset($in['role']))    $fields['role']         = mb_substr(trim((string) $in['role']), 0, 200);

        $allowedStatus = ['live', 'building', 'archived', 'concept'];
        if (isset($in['status']) && in_array($in['status'], $allowedStatus, true)) {
            $fields['status'] = $in['status'];
        }
        if (isset($in['categories']) && is_array($in['categories'])) {
            $cats = array_values(array_filter(array_map(
                fn($c) => mb_substr(trim((string) $c), 0, 40), $in['categories']
            )));
            $fields['categories'] = json_encode($cats, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        }
        if (isset($in['stack']) && is_array($in['stack'])) {
            $stack = array_values(array_filter(array_map(
                fn($c) => mb_substr(trim((string) $c), 0, 40), $in['stack']
            )));
            $fields['stack'] = json_encode($stack, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        }

        // ---- skills: array of { group, items[] } ----------------------------
        if (isset($in['skills']) && is_array($in['skills'])) {
            $skills = [];
            foreach ($in['skills'] as $g) {
                $group = mb_substr(trim((string) ($g['group'] ?? '')), 0, 60);
                $items = array_values(array_filter(array_map(
                    fn($it) => mb_substr(trim((string) $it), 0, 60),
                    (array) ($g['items'] ?? [])
                )));
                if ($group !== '' && $items) {
                    $skills[] = ['group' => $group, 'items' => $items];
                }
            }
            $fields['skills'] = json_encode($skills, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        }

        // ---- metrics: array of { value, label, note? } ----------------------
        if (isset($in['metrics']) && is_array($in['metrics'])) {
            $metrics = [];
            foreach ($in['metrics'] as $m) {
                $value = mb_substr(trim((string) ($m['value'] ?? '')), 0, 40);
                $label = mb_substr(trim((string) ($m['label'] ?? '')), 0, 80);
                if ($value === '' && $label === '') continue;
                $metric = ['value' => $value, 'label' => $label];
                $note = mb_substr(trim((string) ($m['note'] ?? '')), 0, 120);
                if ($note !== '') $metric['note'] = $note;
                $metrics[] = $metric;
            }
            $fields['metrics'] = json_encode($metrics, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        }

        \Db::update('cja_projects', $fields, 'project_id = ?', [$id]);

        $this->json(['ok' => true, 'slug' => $slug]);
    }

    /**
     * Only allow local media paths (uploads live under /media/ or /projects/),
     * never arbitrary or off-site URLs — the src is rendered into the page.
     */
    private function safeMedia(string $s): string
    {
        $s = trim($s);
        if ($s === '') return '';
        return preg_match('#^/(media|projects|portfolio)/[\w./-]+$#', $s) ? $s : '';
    }
}
