// SPDX-License-Identifier: LicenseRef-Commercial
<script lang="ts">
  import {
    proMarketplaceFetchCatalog,
    proMarketplaceInstalled,
    proMarketplaceInstall,
    proMarketplaceUninstall,
    proMarketplaceCheckUpdates,
    proMarketplaceUpdate,
    type CatalogPlugin,
    type InstalledPlugin,
  } from './pro-bridge';

  type Tab = 'browse' | 'installed';

  let tab = $state<Tab>('browse');
  let search = $state('');
  let toast = $state<string | null>(null);
  let toastTimer: ReturnType<typeof setTimeout> | undefined;

  // Browse state
  let catalog = $state<CatalogPlugin[]>([]);
  let catalogLoading = $state(true);
  let catalogError = $state<string | null>(null);
  let selectedPlugin = $state<CatalogPlugin | null>(null);
  let installing = $state<Set<string>>(new Set());

  // Installed state
  let installed = $state<InstalledPlugin[]>([]);
  let installedLoading = $state(true);
  let installedError = $state<string | null>(null);
  let checking = $state(false);
  let uninstalling = $state<Set<string>>(new Set());
  let updating = $state<Set<string>>(new Set());
  let confirmUninstall = $state<string | null>(null);

  let installedIds = $derived(new Set(installed.map((p) => p.id)));

  let filtered = $derived(
    catalog.filter((p) => {
      if (!search) return true;
      const q = search.toLowerCase();
      return (
        p.name.toLowerCase().includes(q) ||
        p.description.toLowerCase().includes(q) ||
        (p.tags ?? []).some((t) => t.toLowerCase().includes(q))
      );
    })
  );

  function showToast(msg: string) {
    toast = msg;
    clearTimeout(toastTimer);
    toastTimer = setTimeout(() => (toast = null), 3000);
  }

  async function loadCatalog() {
    catalogLoading = true;
    catalogError = null;
    try {
      catalog = await proMarketplaceFetchCatalog();
    } catch (e) {
      catalogError = e instanceof Error ? e.message : String(e);
    } finally {
      catalogLoading = false;
    }
  }

  async function loadInstalled() {
    installedLoading = true;
    installedError = null;
    try {
      installed = await proMarketplaceInstalled();
    } catch (e) {
      installedError = e instanceof Error ? e.message : String(e);
    } finally {
      installedLoading = false;
    }
  }

  async function handleInstall(pluginId: string) {
    installing = new Set([...installing, pluginId]);
    try {
      const result = await proMarketplaceInstall(pluginId);
      installed = [...installed, result];
      showToast(`Installed ${result.name} v${result.version}`);
    } catch (e) {
      showToast(`Install failed: ${e instanceof Error ? e.message : String(e)}`);
    } finally {
      const next = new Set(installing);
      next.delete(pluginId);
      installing = next;
    }
  }

  async function handleUninstall(pluginId: string) {
    confirmUninstall = null;
    uninstalling = new Set([...uninstalling, pluginId]);
    const name = installed.find((p) => p.id === pluginId)?.name ?? pluginId;
    try {
      await proMarketplaceUninstall(pluginId);
      installed = installed.filter((p) => p.id !== pluginId);
      showToast(`Uninstalled ${name}`);
    } catch (e) {
      showToast(`Uninstall failed: ${e instanceof Error ? e.message : String(e)}`);
    } finally {
      const next = new Set(uninstalling);
      next.delete(pluginId);
      uninstalling = next;
    }
  }

  async function handleCheckUpdates() {
    checking = true;
    try {
      const updated = await proMarketplaceCheckUpdates();
      installed = updated;
      const count = updated.filter((p) => p.hasUpdate).length;
      showToast(count > 0 ? `${count} update(s) available` : 'All plugins up to date');
    } catch (e) {
      showToast(`Check failed: ${e instanceof Error ? e.message : String(e)}`);
    } finally {
      checking = false;
    }
  }

  async function handleUpdate(pluginId: string) {
    updating = new Set([...updating, pluginId]);
    try {
      const result = await proMarketplaceUpdate(pluginId);
      installed = installed.map((p) => (p.id === pluginId ? result : p));
      showToast(`Updated ${result.name} to v${result.version}`);
    } catch (e) {
      showToast(`Update failed: ${e instanceof Error ? e.message : String(e)}`);
    } finally {
      const next = new Set(updating);
      next.delete(pluginId);
      updating = next;
    }
  }

  function fmtDownloads(n: number | null): string {
    if (n == null) return '';
    if (n >= 1000) return `${(n / 1000).toFixed(1)}k`;
    return String(n);
  }

  function stars(rating: number | null): string {
    if (rating == null) return '';
    const full = Math.round(rating);
    return '\u2605'.repeat(full) + '\u2606'.repeat(5 - full);
  }

  $effect(() => {
    loadCatalog();
    loadInstalled();
  });
</script>

<div class="mp-root">
  <!-- Toast -->
  {#if toast}
    <div class="mp-toast">{toast}</div>
  {/if}

  <!-- Tabs -->
  <div class="mp-tabs">
    <button class="mp-tab" class:active={tab === 'browse'} onclick={() => (tab = 'browse')}>Browse</button>
    <button class="mp-tab" class:active={tab === 'installed'} onclick={() => (tab = 'installed')}>
      Installed{installed.length > 0 ? ` (${installed.length})` : ''}
    </button>
  </div>

  <!-- Browse Tab -->
  {#if tab === 'browse'}
    <div class="mp-search">
      <input type="text" placeholder="Search plugins..." bind:value={search} class="mp-search-input" />
    </div>

    {#if catalogLoading}
      <div class="mp-state">Loading catalog...</div>
    {:else if catalogError}
      <div class="mp-state mp-error">{catalogError}</div>
    {:else if filtered.length === 0}
      <div class="mp-state">{search ? 'No plugins match your search' : 'No plugins available'}</div>
    {:else}
      <div class="mp-grid">
        {#each filtered as plugin (plugin.id)}
          <div class="mp-card" onclick={() => (selectedPlugin = selectedPlugin?.id === plugin.id ? null : plugin)}>
            <div class="mp-card-header">
              <span class="mp-card-name">{plugin.name}</span>
              <span class="mp-card-version">v{plugin.version}</span>
            </div>
            <div class="mp-card-author">by {plugin.author}</div>
            <div class="mp-card-desc">{plugin.description}</div>
            <div class="mp-card-meta">
              {#if plugin.tags}
                <div class="mp-card-tags">
                  {#each plugin.tags.slice(0, 3) as t}
                    <span class="mp-tag">{t}</span>
                  {/each}
                </div>
              {/if}
              <div class="mp-card-stats">
                {#if plugin.downloads != null}<span>{fmtDownloads(plugin.downloads)} dl</span>{/if}
                {#if plugin.rating != null}<span class="mp-stars">{stars(plugin.rating)}</span>{/if}
              </div>
            </div>
            {#if plugin.permissions.length > 0}
              <div class="mp-card-perms">
                {#each plugin.permissions.slice(0, 3) as perm}
                  <span class="mp-perm">{perm}</span>
                {/each}
                {#if plugin.permissions.length > 3}
                  <span class="mp-perm">+{plugin.permissions.length - 3}</span>
                {/if}
              </div>
            {/if}
            <div class="mp-card-actions">
              <button
                class="mp-btn mp-btn-install"
                disabled={installedIds.has(plugin.id) || installing.has(plugin.id)}
                onclick={(e) => { e.stopPropagation(); handleInstall(plugin.id); }}
              >
                {#if installing.has(plugin.id)}
                  Installing...
                {:else if installedIds.has(plugin.id)}
                  Installed
                {:else}
                  Install
                {/if}
              </button>
            </div>
          </div>
        {/each}
      </div>
    {/if}

    <!-- Detail Panel -->
    {#if selectedPlugin}
      <div class="mp-detail">
        <div class="mp-detail-header">
          <h3 class="mp-detail-name">{selectedPlugin.name}</h3>
          <button class="mp-btn-close" onclick={() => (selectedPlugin = null)}>x</button>
        </div>
        <p class="mp-detail-desc">{selectedPlugin.description}</p>
        <div class="mp-detail-fields">
          <div class="mp-field"><span class="mp-field-label">Version</span> {selectedPlugin.version}</div>
          <div class="mp-field"><span class="mp-field-label">Author</span> {selectedPlugin.author}</div>
          {#if selectedPlugin.license}<div class="mp-field"><span class="mp-field-label">License</span> {selectedPlugin.license}</div>{/if}
          {#if selectedPlugin.sizeBytes != null}<div class="mp-field"><span class="mp-field-label">Size</span> {(selectedPlugin.sizeBytes / 1024).toFixed(0)} KB</div>{/if}
          {#if selectedPlugin.minAgorVersion}<div class="mp-field"><span class="mp-field-label">Min Version</span> {selectedPlugin.minAgorVersion}</div>{/if}
        </div>
        {#if selectedPlugin.permissions.length > 0}
          <div class="mp-detail-section">Permissions</div>
          <div class="mp-detail-perms">{#each selectedPlugin.permissions as p}<span class="mp-perm">{p}</span>{/each}</div>
        {/if}
        <div class="mp-detail-links">
          {#if selectedPlugin.homepage}<a href={selectedPlugin.homepage} target="_blank" rel="noopener" class="mp-link">Homepage</a>{/if}
          {#if selectedPlugin.repository}<a href={selectedPlugin.repository} target="_blank" rel="noopener" class="mp-link">Repository</a>{/if}
        </div>
      </div>
    {/if}

  <!-- Installed Tab -->
  {:else}
    <div class="mp-installed-bar">
      <button class="mp-btn" onclick={handleCheckUpdates} disabled={checking}>
        {checking ? 'Checking...' : 'Check for Updates'}
      </button>
    </div>

    {#if installedLoading}
      <div class="mp-state">Loading installed plugins...</div>
    {:else if installedError}
      <div class="mp-state mp-error">{installedError}</div>
    {:else if installed.length === 0}
      <div class="mp-state">No plugins installed. Browse the catalog to get started.</div>
    {:else}
      <div class="mp-installed-list">
        {#each installed as plugin (plugin.id)}
          <div class="mp-installed-item">
            <div class="mp-installed-info">
              <div class="mp-installed-top">
                <span class="mp-card-name">{plugin.name}</span>
                <span class="mp-card-version">v{plugin.version}</span>
                {#if plugin.hasUpdate && plugin.latestVersion}
                  <span class="mp-update-badge">v{plugin.latestVersion} available</span>
                {/if}
              </div>
              <div class="mp-card-author">by {plugin.author}</div>
              <div class="mp-card-desc">{plugin.description}</div>
              {#if plugin.permissions.length > 0}
                <div class="mp-card-perms">
                  {#each plugin.permissions as perm}<span class="mp-perm">{perm}</span>{/each}
                </div>
              {/if}
            </div>
            <div class="mp-installed-actions">
              {#if plugin.hasUpdate}
                <button class="mp-btn mp-btn-install" disabled={updating.has(plugin.id)} onclick={() => handleUpdate(plugin.id)}>
                  {updating.has(plugin.id) ? 'Updating...' : 'Update'}
                </button>
              {/if}
              {#if confirmUninstall === plugin.id}
                <button class="mp-btn mp-btn-danger" onclick={() => handleUninstall(plugin.id)}>Confirm</button>
                <button class="mp-btn" onclick={() => (confirmUninstall = null)}>Cancel</button>
              {:else}
                <button
                  class="mp-btn mp-btn-danger"
                  disabled={uninstalling.has(plugin.id)}
                  onclick={() => (confirmUninstall = plugin.id)}
                >{uninstalling.has(plugin.id) ? 'Removing...' : 'Uninstall'}</button>
              {/if}
            </div>
          </div>
        {/each}
      </div>
    {/if}
  {/if}
</div>

<style>
  .mp-root {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 0.75rem;
    height: 100%;
    overflow-y: auto;
    color: var(--ctp-text);
    font-family: var(--ui-font-family, system-ui, sans-serif);
    font-size: var(--ui-font-size, 0.8125rem);
  }
  .mp-toast {
    position: fixed;
    top: 0.75rem;
    right: 0.75rem;
    padding: 0.5rem 1rem;
    background: var(--ctp-surface1);
    color: var(--ctp-text);
    border: 1px solid var(--ctp-surface2);
    border-radius: 0.375rem;
    font-size: 0.75rem;
    z-index: 999;
    animation: mp-fade-in 0.15s ease-out;
  }
  @keyframes mp-fade-in { from { opacity: 0; transform: translateY(-0.5rem); } }
  .mp-tabs {
    display: flex;
    gap: 0.25rem;
    border-bottom: 1px solid var(--ctp-surface0);
    padding-bottom: 0.25rem;
  }
  .mp-tab {
    padding: 0.375rem 0.75rem;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--ctp-subtext0);
    cursor: pointer;
    font-size: 0.8125rem;
  }
  .mp-tab:hover { color: var(--ctp-text); }
  .mp-tab.active { color: var(--ctp-blue); border-bottom-color: var(--ctp-blue); }
  .mp-search { display: flex; }
  .mp-search-input {
    flex: 1;
    padding: 0.375rem 0.625rem;
    background: var(--ctp-surface0);
    border: 1px solid var(--ctp-surface1);
    border-radius: 0.375rem;
    color: var(--ctp-text);
    font-size: 0.8125rem;
    outline: none;
  }
  .mp-search-input::placeholder { color: var(--ctp-overlay0); }
  .mp-search-input:focus { border-color: var(--ctp-blue); }
  .mp-state { padding: 2rem; text-align: center; color: var(--ctp-subtext0); }
  .mp-error { color: var(--ctp-red); }
  .mp-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    gap: 0.5rem;
  }
  .mp-card {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 0.625rem;
    background: var(--ctp-surface0);
    border: 1px solid var(--ctp-surface1);
    border-radius: 0.375rem;
    cursor: pointer;
    transition: border-color 0.1s;
  }
  .mp-card:hover { border-color: var(--ctp-blue); }
  .mp-card-header { display: flex; align-items: baseline; gap: 0.375rem; }
  .mp-card-name { font-weight: 600; color: var(--ctp-text); }
  .mp-card-version { font-size: 0.6875rem; color: var(--ctp-overlay0); font-family: monospace; }
  .mp-card-author { font-size: 0.6875rem; color: var(--ctp-subtext0); }
  .mp-card-desc {
    font-size: 0.75rem;
    color: var(--ctp-subtext1);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .mp-card-meta { display: flex; justify-content: space-between; align-items: center; gap: 0.25rem; }
  .mp-card-tags { display: flex; gap: 0.25rem; flex-wrap: wrap; }
  .mp-tag {
    font-size: 0.625rem;
    padding: 0.0625rem 0.375rem;
    background: color-mix(in srgb, var(--ctp-blue) 15%, transparent);
    color: var(--ctp-blue);
    border-radius: 0.25rem;
  }
  .mp-card-stats { display: flex; gap: 0.5rem; font-size: 0.6875rem; color: var(--ctp-overlay1); }
  .mp-stars { color: var(--ctp-yellow); letter-spacing: 0.05em; }
  .mp-card-perms { display: flex; gap: 0.25rem; flex-wrap: wrap; }
  .mp-perm {
    font-size: 0.625rem;
    padding: 0.0625rem 0.375rem;
    background: color-mix(in srgb, var(--ctp-peach) 12%, transparent);
    color: var(--ctp-peach);
    border-radius: 0.25rem;
  }
  .mp-card-actions { margin-top: 0.25rem; display: flex; justify-content: flex-end; }
  .mp-btn {
    padding: 0.25rem 0.75rem;
    border: 1px solid var(--ctp-surface1);
    border-radius: 0.25rem;
    background: var(--ctp-surface0);
    color: var(--ctp-subtext0);
    cursor: pointer;
    font-size: 0.75rem;
  }
  .mp-btn:hover:not(:disabled) { background: var(--ctp-surface1); color: var(--ctp-text); }
  .mp-btn:disabled { opacity: 0.4; cursor: default; }
  .mp-btn-install {
    background: var(--ctp-blue);
    color: var(--ctp-base);
    border-color: var(--ctp-blue);
  }
  .mp-btn-install:hover:not(:disabled) { opacity: 0.9; background: var(--ctp-blue); color: var(--ctp-base); }
  .mp-btn-danger { color: var(--ctp-red); border-color: var(--ctp-red); background: none; }
  .mp-btn-danger:hover:not(:disabled) {
    background: color-mix(in srgb, var(--ctp-red) 12%, transparent);
    color: var(--ctp-red);
  }
  .mp-btn-close {
    background: none;
    border: none;
    color: var(--ctp-overlay0);
    cursor: pointer;
    font-size: 1rem;
    padding: 0.125rem 0.375rem;
  }
  .mp-btn-close:hover { color: var(--ctp-text); }
  .mp-detail {
    background: var(--ctp-mantle);
    border: 1px solid var(--ctp-surface1);
    border-radius: 0.375rem;
    padding: 0.75rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }
  .mp-detail-header { display: flex; justify-content: space-between; align-items: center; }
  .mp-detail-name { margin: 0; font-size: 1rem; font-weight: 600; color: var(--ctp-text); }
  .mp-detail-desc { font-size: 0.8125rem; color: var(--ctp-subtext1); margin: 0; line-height: 1.5; }
  .mp-detail-fields { display: flex; flex-wrap: wrap; gap: 0.375rem 1rem; font-size: 0.75rem; color: var(--ctp-subtext1); }
  .mp-field-label { color: var(--ctp-subtext0); margin-right: 0.25rem; }
  .mp-detail-section { font-size: 0.6875rem; color: var(--ctp-subtext0); text-transform: uppercase; letter-spacing: 0.04em; }
  .mp-detail-perms { display: flex; gap: 0.25rem; flex-wrap: wrap; }
  .mp-detail-links { display: flex; gap: 0.75rem; }
  .mp-link { font-size: 0.75rem; color: var(--ctp-blue); text-decoration: none; }
  .mp-link:hover { text-decoration: underline; }
  .mp-installed-bar { display: flex; justify-content: flex-end; }
  .mp-installed-list { display: flex; flex-direction: column; gap: 0.375rem; }
  .mp-installed-item {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.625rem;
    background: var(--ctp-surface0);
    border: 1px solid var(--ctp-surface1);
    border-radius: 0.375rem;
  }
  .mp-installed-info { flex: 1; display: flex; flex-direction: column; gap: 0.25rem; }
  .mp-installed-top { display: flex; align-items: baseline; gap: 0.375rem; }
  .mp-update-badge {
    font-size: 0.625rem;
    padding: 0.0625rem 0.375rem;
    background: color-mix(in srgb, var(--ctp-green) 15%, transparent);
    color: var(--ctp-green);
    border-radius: 0.25rem;
  }
  .mp-installed-actions { display: flex; gap: 0.375rem; flex-shrink: 0; align-items: center; }
</style>
