<?php
declare(strict_types=1);

require __DIR__ . '/../../includes/bootstrap.php';
require_admin_login();

$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
$pageTitle = $id ? 'Edit Project | Admin' : 'New Project | Admin';

// bring optional columns up-to-date (idempotent)
try {
  $cols = pdo()->query("SHOW COLUMNS FROM projects")->fetchAll(PDO::FETCH_ASSOC);
  $colNames = array_map(static fn($c) => (string)($c['Field'] ?? ''), $cols);
  $alter = [];

  if (!in_array('tech_json', $colNames, true))     $alter[] = "ADD COLUMN tech_json LONGTEXT NULL";
  if (!in_array('links_json', $colNames, true))    $alter[] = "ADD COLUMN links_json LONGTEXT NULL";
  if (!in_array('sort_order', $colNames, true))    $alter[] = "ADD COLUMN sort_order INT NOT NULL DEFAULT 0";
  if (!in_array('slug', $colNames, true))          $alter[] = "ADD COLUMN slug VARCHAR(120) NULL";
  if (!in_array('short_summary', $colNames, true)) $alter[] = "ADD COLUMN short_summary VARCHAR(240) NULL";

  foreach ($cols as $c) {
    if (($c['Field'] ?? '') !== 'summary') continue;
    $type = strtolower((string)($c['Type'] ?? ''));
    $null = strtoupper((string)($c['Null'] ?? '')) === 'YES' ? 'NULL' : 'NOT NULL';
    if (strpos($type, 'text') === false) $alter[] = "MODIFY summary TEXT {$null}";
    break;
  }
  if ($alter) {
    pdo()->exec("ALTER TABLE projects " . implode(", ", $alter));
  }
} catch (Throwable $e) {}

$project = [
  'slug' => '',
  'title' => '',
  'tag' => '',
  'year' => (int)date('Y'),
  'summary' => '',
  'short_summary' => '',
  'tech_json' => '[]',
  'links_json' => '[]',
  'sort_order' => 0,
];

$activeTab = (isset($_GET['tab']) && strtolower((string)$_GET['tab']) === 'gallery') ? 'gallery' : 'details';

if ($id) {
  $st = pdo()->prepare("SELECT id, slug, title, tag, year, summary, short_summary, tech_json, links_json, sort_order FROM projects WHERE id = ? LIMIT 1");
  $st->execute([$id]);
  $row = $st->fetch(PDO::FETCH_ASSOC);

  if (!$row) {
    flash_set('danger', 'Project not found.');
    header('Location: /public/admin/projects.php');
    exit;
  }
  $project = $row;
}

$errors = [];

function parse_list(string $raw): array {
  $parts = preg_split('/[\r\n,]+/', $raw) ?: [];
  $out = [];
  foreach ($parts as $p) {
    $p = trim((string)$p);
    if ($p !== '') $out[] = $p;
  }
  return array_values(array_unique($out));
}

function parse_links(string $raw): array {
  $lines = preg_split('/\R/', $raw) ?: [];
  $links = [];
  foreach ($lines as $ln) {
    $ln = trim((string)$ln);
    if ($ln === '') continue;

    // Format: Label | https://...
    $label = $ln;
    $url = '';
    if (strpos($ln, '|') !== false) {
      [$label, $url] = array_map('trim', explode('|', $ln, 2));
    }

    if ($url === '' || !filter_var($url, FILTER_VALIDATE_URL)) continue;
    if ($label === '') $label = 'Link';

    $links[] = ['label' => $label, 'url' => $url];
  }
  return $links;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  if (!csrf_check((string)($_POST['csrf'] ?? ''))) {
    $errors[] = 'CSRF failed. Refresh and try again.';
  }

  $slugRaw = trim((string)($_POST['slug'] ?? ''));
  $title   = trim((string)($_POST['title'] ?? ''));
  $tag     = trim((string)($_POST['tag'] ?? ''));
  $year    = (int)($_POST['year'] ?? 0);
  $summary = trim((string)($_POST['summary'] ?? ''));
  $shortSummary = trim((string)($_POST['short_summary'] ?? ''));
  $techRaw = (string)($_POST['tech'] ?? '');
  $linksRaw= (string)($_POST['links'] ?? '');
  $sort    = (int)($_POST['sort_order'] ?? 0);

  $slug = project_slugify($slugRaw !== '' ? $slugRaw : $title);
  if ($slug === '' && $title !== '') $slug = project_slugify($title);

  if ($slug === '' || !preg_match('/^[a-z0-9-]{2,120}$/', $slug)) $errors[] = 'Slug must be letters, numbers, or hyphen (auto-derived from title).';
  if ($title === '' || mb_strlen($title) > 140) $errors[] = 'Title must be 1-140 chars.';
  if ($tag === '' || mb_strlen($tag) > 50) $errors[] = 'Tag must be 1-50 chars.';
  if ($year < 2000 || $year > 2100) $errors[] = 'Year must be 2000-2100.';
  if ($summary === '' || mb_strlen($summary) > 5000) $errors[] = 'Summary is required (max 5000 chars).';
  if ($shortSummary !== '' && mb_strlen($shortSummary) > 240) $errors[] = 'Card summary must be 240 chars or less.';

  $tech  = parse_list($techRaw);
  $links = parse_links($linksRaw);

  $techJson  = json_encode($tech, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
  $linksJson = json_encode($links, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

  if ($slug !== '') {
    $st = pdo()->prepare("SELECT id FROM projects WHERE slug = ? AND id <> ? LIMIT 1");
    $st->execute([$slug, $id]);
    if ($st->fetch()) $errors[] = 'Slug already in use.';
  }

  if (!$errors) {
    if ($id) {
      $st = pdo()->prepare("UPDATE projects SET slug=?, title=?, tag=?, year=?, summary=?, short_summary=?, tech_json=?, links_json=?, sort_order=? WHERE id=?");
      $st->execute([$slug, $title, $tag, $year, $summary, $shortSummary ?: null, $techJson, $linksJson, $sort, $id]);
      flash_set('success', 'Project updated.');
    } else {
      $st = pdo()->prepare("INSERT INTO projects (slug, title, tag, year, summary, short_summary, tech_json, links_json, sort_order) VALUES (?,?,?,?,?,?,?,?,?)");
      $st->execute([$slug, $title, $tag, $year, $summary, $shortSummary ?: null, $techJson, $linksJson, $sort]);
      flash_set('success', 'Project created.');
    }

    header('Location: /public/admin/projects.php');
    exit;
  }

  // repopulate if validation fails
  $project['slug'] = $slug;
  $project['title'] = $title;
  $project['tag'] = $tag;
  $project['year'] = $year;
  $project['summary'] = $summary;
  $project['short_summary'] = $shortSummary;
  $project['tech_json'] = $techJson;
  $project['links_json'] = $linksJson;
  $project['sort_order'] = $sort;
}

// Prefill textareas
$techArr = json_decode((string)($project['tech_json'] ?? '[]'), true);
$techTxt = is_array($techArr) ? implode("\n", $techArr) : '';

$linksArr = json_decode((string)($project['links_json'] ?? '[]'), true);
$linksTxt = '';
if (is_array($linksArr)) {
  foreach ($linksArr as $l) {
    $lbl = (string)($l['label'] ?? '');
    $url = (string)($l['url'] ?? '');
    if ($url !== '') $linksTxt .= "{$lbl} | {$url}\n";
  }
}
$linksTxt = trim($linksTxt);
$mediaEndpoint = url_path('/public/admin/project_media.php');
$projectFolder = $id ? project_media_folder($project) : '';

include __DIR__ . '/_top.php';
?>

<div class="d-flex align-items-center justify-content-between mt-4 flex-wrap gap-2">
  <h1 class="h3 m-0 brand"><?= $id ? 'Edit Project' : 'New Project' ?></h1>
  <a class="btn btn-outline-light" href="/public/admin/projects.php">Back</a>
</div>

<?php if ($errors): ?>
  <div class="alert alert-danger card-glass border-0 mt-3">
    <ul class="mb-0">
      <?php foreach ($errors as $e): ?><li><?= htmlspecialchars($e) ?></li><?php endforeach; ?>
    </ul>
  </div>
<?php endif; ?>

<div class="card card-glass border-0 mt-3 p-4">
  <ul class="nav nav-pills gap-2" id="projectTabs" role="tablist">
    <li class="nav-item" role="presentation">
      <button class="nav-link <?= $activeTab === 'details' ? 'active' : '' ?>" id="tabDetailsBtn" data-bs-toggle="tab" data-bs-target="#tabDetails" type="button" role="tab" aria-controls="tabDetails" aria-selected="<?= $activeTab === 'details' ? 'true' : 'false' ?>">
        Details
      </button>
    </li>
    <li class="nav-item" role="presentation">
      <button class="nav-link <?= $activeTab === 'gallery' ? 'active' : '' ?>" id="tabGalleryBtn" data-bs-toggle="tab" data-bs-target="#tabGallery" type="button" role="tab" aria-controls="tabGallery" aria-selected="<?= $activeTab === 'gallery' ? 'true' : 'false' ?>">
        Gallery
      </button>
    </li>
  </ul>

  <div class="tab-content mt-3">
    <div class="tab-pane fade <?= $activeTab === 'details' ? 'show active' : '' ?>" id="tabDetails" role="tabpanel" aria-labelledby="tabDetailsBtn">
      <form method="post">
        <input type="hidden" name="csrf" value="<?= htmlspecialchars(csrf_token()) ?>">

        <div class="row g-3">
          <div class="col-md-6">
            <label class="form-label text-white-50">Title</label>
            <input class="form-control" name="title" maxlength="140" required
                   value="<?= htmlspecialchars((string)$project['title']) ?>">
          </div>

          <div class="col-md-3">
            <label class="form-label text-white-50">Year</label>
            <input class="form-control" name="year" type="number" min="2000" max="2100" required
                   value="<?= (int)$project['year'] ?>">
          </div>

          <div class="col-md-3">
            <label class="form-label text-white-50">Tag</label>
            <input class="form-control" name="tag" maxlength="50" required
                   value="<?= htmlspecialchars((string)$project['tag']) ?>">
          </div>

      <div class="col-md-6">
        <label class="form-label text-white-50">Slug (auto)</label>
        <input class="form-control" name="slug" maxlength="120"
               value="<?= htmlspecialchars((string)($project['slug'] ?? '')) ?>"
               placeholder="my-project-name">
        <div class="form-text text-white-50">Letters, numbers, and hyphen. Lowercase slug is auto-built from the title.</div>
      </div>

          <div class="col-md-3">
            <label class="form-label text-white-50">Sort order</label>
            <input class="form-control" name="sort_order" type="number" value="<?= (int)($project['sort_order'] ?? 0) ?>">
          </div>

          <div class="col-12">
            <label class="form-label text-white-50">Summary</label>
            <textarea class="form-control" name="summary" rows="4" required><?= htmlspecialchars((string)$project['summary']) ?></textarea>
          </div>
          <div class="col-12">
            <label class="form-label text-white-50">Card summary (optional, short preview)</label>
            <textarea class="form-control" name="short_summary" rows="2" maxlength="240"
                      placeholder="If blank, the preview will clamp the full summary."><?= htmlspecialchars((string)($project['short_summary'] ?? '')) ?></textarea>
          </div>

          <div class="col-md-6">
            <label class="form-label text-white-50">Tech (one per line OR comma separated)</label>
            <textarea class="form-control" name="tech" rows="7" placeholder="PHP&#10;MariaDB&#10;jQuery"><?= htmlspecialchars($techTxt) ?></textarea>
          </div>

          <div class="col-md-6">
            <label class="form-label text-white-50">Links (one per line): <code>Label | https://url</code></label>
            <textarea class="form-control" name="links" rows="7" placeholder="Repo | https://github.com/..."><?= htmlspecialchars($linksTxt) ?></textarea>
          </div>
        </div>

        <div class="mt-4 d-flex gap-2">
          <button class="btn btn-violet"><?= $id ? 'Save Changes' : 'Create Project' ?></button>
          <a class="btn btn-outline-light" href="/public/admin/projects.php">Cancel</a>
        </div>
      </form>
    </div>

    <div class="tab-pane fade <?= $activeTab === 'gallery' ? 'show active' : '' ?>" id="tabGallery" role="tabpanel" aria-labelledby="tabGalleryBtn">
      <?php if (!$id): ?>
        <div class="alert alert-info card-glass border-0 mt-3">
          Save the project first to unlock the media gallery.
        </div>
      <?php else: ?>
        <div id="mediaManager"
             data-project-id="<?= (int)$id ?>"
             data-csrf="<?= htmlspecialchars(csrf_token()) ?>"
             data-endpoint="<?= htmlspecialchars($mediaEndpoint) ?>">
          <div class="d-flex flex-wrap justify-content-between gap-2 mb-3">
            <div>
              <div class="text-white-50 small">Files live in</div>
              <div class="fw-bold">Project imgs/<?= htmlspecialchars($projectFolder) ?></div>
            </div>
            <div class="text-white-50 small">JPEG, PNG or WebP up to 8MB; re-encoded via GD.</div>
          </div>

          <div class="row g-3 align-items-stretch">
            <div class="col-lg-5">
              <div id="mediaDrop" class="media-drop rounded-3" role="button" tabindex="0">
                <div class="text-center">
                  <div class="fw-semibold">Drag &amp; drop screenshots</div>
                  <div class="text-white-50 small">or click to pick files</div>
                </div>
                <input type="file" id="mediaInput" accept="image/*" multiple hidden>
              </div>
              <div class="small text-white-50 mt-2">Paste an image URL and we'll fetch and sanitize it.</div>
              <div class="input-group mt-2">
                <input type="url" class="form-control" id="mediaUrlInput" placeholder="https://example.com/screenshot.jpg">
                <button class="btn btn-outline-light" type="button" id="mediaUrlBtn">Add URL</button>
              </div>
              <div class="small mt-2" id="mediaStatus" aria-live="polite"></div>
            </div>
            <div class="col-lg-7">
              <div class="media-grid" id="mediaGrid" aria-live="polite"></div>
            </div>
          </div>
        </div>
      <?php endif; ?>
    </div>
  </div>
</div>

<script>
(function ($) {
  $(function () {
    const $manager = $("#mediaManager");
    if (!$manager.length) return;

    const endpoint = $manager.data("endpoint");
    const projectId = $manager.data("project-id");
    const csrf = $manager.data("csrf");
    const $drop = $("#mediaDrop");
    const $input = $("#mediaInput");
    const $grid = $("#mediaGrid");
    const $status = $("#mediaStatus");
    const $urlInput = $("#mediaUrlInput");
    const $urlBtn = $("#mediaUrlBtn");

    const setStatus = (msg, type) => {
      if (!$status.length) return;
      const cls = type === "error" ? "text-danger" : (type === "success" ? "text-success" : "text-white-50");
      $status.attr("class", "small mt-2 " + cls).text(msg || "");
    };

    const bytesToSize = (bytes) => {
      if (!bytes) return "0 KB";
      const kb = bytes / 1024;
      if (kb < 1024) return kb.toFixed(1) + " KB";
      return (kb / 1024).toFixed(1) + " MB";
    };

    const render = (files) => {
      if (!$grid.length) return;
      $grid.empty();
      if (!files || !files.length) {
        $("<div/>", { class: "text-white-50 small" })
          .text("No images yet. Drop files or paste a URL to begin.")
          .appendTo($grid);
        return;
      }

      files.forEach((f) => {
        const sizeLabel = bytesToSize(f.size || 0);
        const $card = $("<div/>", { class: "media-card" });

        $("<img/>", { src: f.url, alt: f.name }).appendTo($card);

        $("<div/>", { class: "media-meta" })
          .html(
            '<div class="fw-semibold small text-truncate">' + f.name + "</div>" +
            '<div class="text-white-50 small">' +
            (f.width || "?") + "x" + (f.height || "?") + " - " + sizeLabel + "</div>"
          )
          .appendTo($card);

        $("<div/>", { class: "media-actions" })
          .append(
            $("<button/>", {
              type: "button",
              class: "btn btn-sm btn-outline-light",
              text: "Delete"
            }).on("click", function () {
              if (confirm("Remove this image?")) deleteFile(f.name);
            })
          )
          .appendTo($card);

        $grid.append($card);
      });
    };

    const fetchList = () => {
      setStatus("Loading images...");
      return $.ajax({
        url: `${endpoint}?action=list&project_id=${encodeURIComponent(projectId)}&csrf=${encodeURIComponent(csrf)}`,
        method: "GET",
        dataType: "json",
        cache: false
      })
        .done((data) => {
          if (!data || data.ok !== true) {
            setStatus((data && data.error) ? data.error : "Unable to load images", "error");
            return;
          }
          render(data.files || []);
          const files = data.files || [];
          setStatus(files.length ? "" : "Drop files or paste a URL to upload.", "muted");
        })
        .fail((xhr) => {
          const msg = (xhr && xhr.responseJSON && xhr.responseJSON.error) || xhr.statusText || "Failed to load images";
          setStatus(msg, "error");
        });
    };

    const uploadFiles = (list) => {
      const files = Array.from(list || []).filter((f) => (f.type || "").startsWith("image/"));
      if (!files.length) {
        setStatus("Only image files are accepted.", "error");
        return;
      }
      setStatus("Uploading...", "muted");
      const form = new FormData();
      form.append("action", "upload");
      form.append("project_id", projectId);
      form.append("csrf", csrf);
      files.slice(0, 10).forEach((f) => form.append("files[]", f));

      $.ajax({
        url: endpoint,
        method: "POST",
        data: form,
        processData: false,
        contentType: false,
        cache: false,
        dataType: "json"
      })
        .done((data) => {
          if (!data || data.ok !== true) {
            setStatus((data && data.error) ? data.error : "Upload failed", "error");
            return;
          }
          setStatus(`Saved ${data.saved || 0} file(s).`, "success");
          fetchList();
        })
        .fail((xhr) => {
          const msg = (xhr && xhr.responseJSON && xhr.responseJSON.error) || xhr.statusText || "Upload failed";
          setStatus(msg, "error");
        });
    };

    const importUrl = () => {
      const url = ($urlInput.val() || "").trim();
      if (!url) {
        setStatus("Paste an image URL first.", "error");
        return;
      }
      setStatus("Fetching URL...", "muted");
      const form = new FormData();
      form.append("action", "fetch_url");
      form.append("project_id", projectId);
      form.append("csrf", csrf);
      form.append("image_url", url);

      $.ajax({
        url: endpoint,
        method: "POST",
        data: form,
        processData: false,
        contentType: false,
        cache: false,
        dataType: "json"
      })
        .done((data) => {
          if (!data || data.ok !== true) {
            setStatus((data && data.error) ? data.error : "Import failed", "error");
            return;
          }
          setStatus("Image imported.", "success");
          $urlInput.val("");
          fetchList();
        })
        .fail((xhr) => {
          const msg = (xhr && xhr.responseJSON && xhr.responseJSON.error) || xhr.statusText || "Import failed";
          setStatus(msg, "error");
        });
    };

    const deleteFile = (name) => {
      const form = new FormData();
      form.append("action", "delete");
      form.append("project_id", projectId);
      form.append("csrf", csrf);
      form.append("name", name);

      $.ajax({
        url: endpoint,
        method: "POST",
        data: form,
        processData: false,
        contentType: false,
        cache: false,
        dataType: "json"
      })
        .done((data) => {
          if (!data || data.ok !== true) {
            setStatus((data && data.error) ? data.error : "Delete failed", "error");
            return;
          }
          setStatus("Image removed.", "success");
          fetchList();
        })
        .fail((xhr) => {
          const msg = (xhr && xhr.responseJSON && xhr.responseJSON.error) || xhr.statusText || "Delete failed";
          setStatus(msg, "error");
        });
    };

    if ($drop.length && $input.length) {
      $drop.on("dragenter dragover", (e) => {
        e.preventDefault();
        $drop.addClass("is-drag");
      });
      $drop.on("dragleave drop", (e) => {
        e.preventDefault();
        $drop.removeClass("is-drag");
      });
      $drop.on("drop", (e) => {
        e.preventDefault();
        $drop.removeClass("is-drag");
        uploadFiles(e.originalEvent.dataTransfer.files);
      });
      $drop.on("click", () => $input.trigger("click"));
      $drop.on("keydown", (e) => {
        if (e.key === "Enter" || e.key === " ") {
          e.preventDefault();
          $input.trigger("click");
        }
      });
      $input.on("change", function () {
        uploadFiles(this.files);
        this.value = "";
      });
    }

    if ($urlBtn.length) $urlBtn.on("click", importUrl);
    if ($urlInput.length) {
      $urlInput.on("keydown", (e) => {
        if (e.key === "Enter") {
          e.preventDefault();
          importUrl();
        }
      });
    }

    fetchList();
  });
})(jQuery);
</script>


<link rel="stylesheet" href="/public/css/edit_project.css">
<?php include __DIR__ . '/_bottom.php'; ?>
