<script>
  import { onMount } from 'svelte';
  import { push } from 'svelte-spa-router';
  import { auth } from '../lib/stores/auth.js';
  import { navContext } from '../lib/stores/navContext.js';
  import { fetchMyDecks, togglePublished, getMyDeckRating, submitDeckRating, getSourceUpdatePreview, applySourceUpdate, deleteDeck } from '../lib/api/decks.js';
  import RatingModal from '../lib/RatingModal.svelte';
  import ConfirmModal from '../lib/ConfirmModal.svelte';

  onMount(() => {
    navContext.set('my-decks');
  });

  let decks = [];
  let loading = true;
  let error = null;
  let ratingDeck = null;
  let ratingInitial = { rating: 0, comment: '' };
  let showUnpublishConfirm = false;
  let deckToUnpublish = null;
  let showUpdateModal = false;
  let updateDeck = null;
  let updatePreview = null;
  let updateLoading = false;
  let updateError = null;
  let updateApplying = false;
  let showRemoveConfirm = false;
  let deckToRemove = null;

  $: userId = $auth.user?.id;

  function formatRating(n) {
    return Number(n).toFixed(1);
  }

  async function openRatingModal(deck, e) {
    e?.stopPropagation();
    if (!deck.can_rate || !deck.rateable_deck_id || !userId) return;
    ratingDeck = { id: deck.rateable_deck_id, title: deck.source_deck_title ?? 'Deck' };
    try {
      const data = await getMyDeckRating(deck.rateable_deck_id, userId);
      ratingInitial = { rating: data?.rating ?? 0, comment: data?.comment ?? '' };
    } catch (_) {
      ratingInitial = { rating: 0, comment: '' };
    }
  }

  function closeRatingModal() {
    ratingDeck = null;
  }

  async function handleRatingSubmit(payload) {
    if (!ratingDeck || !userId) return;
    try {
      await submitDeckRating(ratingDeck.id, userId, payload);
      await load();
    } catch (_) {}
  }

  let prevUserId = null;
  $: if (!$auth.loading && userId && userId !== prevUserId) {
    prevUserId = userId;
    load();
  } else if (!$auth.loading && !userId) {
    loading = false;
    prevUserId = null;
  }

  async function load() {
    if (!userId) return;
    loading = true;
    error = null;
    try {
      decks = await fetchMyDecks(userId);
    } catch (e) {
      error = e?.message ?? 'Failed to load decks';
      decks = [];
    } finally {
      loading = false;
    }
  }

  function goEdit(id) {
    push(`/decks/${id}/edit`);
  }

  function goPreview(deck) {
    push(`/decks/${deck.id}/preview`);
  }

  let togglingId = null;
  async function handlePublish(e, deck) {
    e.stopPropagation();
    e.preventDefault();
    if (togglingId === deck.id) return;
    togglingId = deck.id;
    try {
      await togglePublished(deck.id, true);
      decks = decks.map((d) => (d.id === deck.id ? { ...d, published: true } : d));
    } catch (err) {
      error = err?.message ?? 'Failed to update publish status';
    } finally {
      togglingId = null;
    }
  }

  function openUnpublishConfirm(e, deck) {
    e.stopPropagation();
    e.preventDefault();
    deckToUnpublish = deck;
    showUnpublishConfirm = true;
  }

  function closeUnpublishConfirm() {
    showUnpublishConfirm = false;
    deckToUnpublish = null;
  }

  async function confirmUnpublish() {
    if (!deckToUnpublish) return;
    const deck = deckToUnpublish;
    closeUnpublishConfirm();
    togglingId = deck.id;
    try {
      await togglePublished(deck.id, false);
      decks = decks.map((d) => (d.id === deck.id ? { ...d, published: false } : d));
    } catch (err) {
      error = err?.message ?? 'Failed to update publish status';
    } finally {
      togglingId = null;
    }
  }

  async function openUpdateModal(deck, e) {
    e?.stopPropagation();
    e?.preventDefault();
    if (!deck?.needs_update || !userId) return;
    updateDeck = deck;
    showUpdateModal = true;
    updatePreview = null;
    updateError = null;
    updateLoading = true;
    try {
      updatePreview = await getSourceUpdatePreview(deck.id, userId);
    } catch (err) {
      updateError = err?.message ?? 'Failed to load update preview';
    } finally {
      updateLoading = false;
    }
  }

  function closeUpdateModal() {
    showUpdateModal = false;
    updateDeck = null;
    updatePreview = null;
    updateError = null;
    updateApplying = false;
  }

  async function confirmSourceUpdate() {
    if (!updateDeck || !userId) return;
    updateApplying = true;
    updateError = null;
    try {
      await applySourceUpdate(updateDeck.id, userId);
      await load();
      closeUpdateModal();
    } catch (err) {
      updateError = err?.message ?? 'Failed to update deck';
    } finally {
      updateApplying = false;
    }
  }

  function openRemoveConfirm(deck, e) {
    e?.stopPropagation();
    e?.preventDefault();
    if (!deck?.copied_from_deck_id) return;
    deckToRemove = deck;
    showRemoveConfirm = true;
  }

  function closeRemoveConfirm() {
    showRemoveConfirm = false;
    deckToRemove = null;
  }

  async function confirmRemoveFromMyDecks() {
    if (!deckToRemove) return;
    const deck = deckToRemove;
    closeRemoveConfirm();
    try {
      await deleteDeck(deck.id);
      await load();
    } catch (err) {
      error = err?.message ?? 'Failed to remove deck';
    }
  }
</script>

<div class="page">
  <header class="page-header">
    <h1>My decks</h1>
  </header>

  {#if $auth.loading}
    <p class="muted">Loading…</p>
  {:else if !userId}
    <p class="auth-required">Sign in to create and manage your decks.</p>
  {:else if loading}
    <p class="muted">Loading…</p>
  {:else if error}
    <p class="error">{error}</p>
  {:else if decks.length === 0}
    <p class="muted">No decks yet. Create your first deck to get started.</p>
  {:else}
    <ul class="deck-grid">
      {#each decks as deck (deck.id)}
        <li class="deck-card">
          <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
          <div
            class="deck-card-inner"
            onclick={() => goPreview(deck)}
            onkeydown={(e) => e.key === 'Enter' && goPreview(deck)}
            role="button"
            tabindex="0"
          >
            <h3 class="deck-title">{deck.title}</h3>
            {#if deck.description}
              <p class="deck-description">{deck.description}</p>
            {/if}
            <div class="deck-meta">
              <span class="deck-count">{deck.question_count ?? 0} questions</span>
            </div>
            {#if (deck.average_rating ?? 0) > 0 || (deck.rating_count ?? 0) > 0 || deck.can_rate}
              {#if deck.can_rate}
                <button
                  type="button"
                  class="deck-rating clickable"
                  aria-label="Rating: {deck.average_rating ?? 0} out of 5 stars"
                  onclick={(e) => openRatingModal(deck, e)}
                  onkeydown={(e) => e.key === 'Enter' && openRatingModal(deck, e)}
                >
                  <span class="stars">{['★', '★', '★', '★', '★'].map((_, i) => (i < Math.round(deck.average_rating ?? 0) ? '★' : '☆')).join('')}</span>
                  <span class="rating-text">{formatRating(deck.average_rating ?? 0)}</span>
                  {#if (deck.rating_count ?? 0) > 0}
                    <span class="rating-count">({deck.rating_count})</span>
                  {/if}
                </button>
              {:else}
                <div class="deck-rating" aria-label="Rating: {deck.average_rating ?? 0} out of 5 stars">
                  <span class="stars">{['★', '★', '★', '★', '★'].map((_, i) => (i < Math.round(deck.average_rating ?? 0) ? '★' : '☆')).join('')}</span>
                  <span class="rating-text">{formatRating(deck.average_rating ?? 0)}</span>
                  {#if (deck.rating_count ?? 0) > 0}
                    <span class="rating-count">({deck.rating_count})</span>
                  {/if}
                </div>
              {/if}
            {/if}
            <div class="deck-card-actions">
              {#if deck.needs_update}
                <button
                  type="button"
                  class="btn btn-icon btn-icon-update"
                  onclick={(e) => openUpdateModal(deck, e)}
                  title="Update from community (v{deck.source_version ?? 1} available)"
                  aria-label="Update from community (v{deck.source_version ?? 1} available)"
                >
                  <span class="update-icon-wrap">
                    <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                      <path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/>
                      <path d="M3 3v5h5"/>
                      <path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16"/>
                      <path d="M16 21h5v-5"/>
                    </svg>
                  </span>
                  <span class="update-badge" aria-hidden="true">{deck.source_version ?? 1}</span>
                </button>
              {/if}
              {#if !deck.copied_from_deck_id}
                {#if deck.published}
                  <button
                    type="button"
                    class="btn btn-small btn-published"
                    onclick={(e) => openUnpublishConfirm(e, deck)}
                    disabled={togglingId === deck.id}
                    title="Click to unpublish"
                  >
                    {togglingId === deck.id ? '…' : 'Published'}
                  </button>
                {:else}
                  <button
                    type="button"
                    class="btn btn-small btn-secondary"
                    onclick={(e) => handlePublish(e, deck)}
                    disabled={togglingId === deck.id}
                  >
                    {togglingId === deck.id ? '…' : 'Publish'}
                  </button>
                {/if}
              {/if}
              {#if !deck.copied_from_deck_id}
                <button type="button" class="btn btn-icon" onclick={(e) => { e.stopPropagation(); goEdit(deck.id); }} title="Edit deck" aria-label="Edit deck">
                  <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
                    <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
                  </svg>
                </button>
              {:else}
                <button
                  type="button"
                  class="btn btn-icon btn-icon-danger"
                  onclick={(e) => openRemoveConfirm(deck, e)}
                  title="Remove from My decks"
                  aria-label="Remove from My decks"
                >
                  <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/>
                  </svg>
                </button>
              {/if}
            </div>
          </div>
        </li>
      {/each}
    </ul>
  {/if}

  <RatingModal
    deck={ratingDeck}
    initialRating={ratingInitial.rating}
    initialComment={ratingInitial.comment}
    onSubmit={handleRatingSubmit}
    onClose={closeRatingModal}
  />

  <ConfirmModal
    open={showUnpublishConfirm}
    title="Unpublish deck"
    message="Unpublish this deck? It will no longer be visible in Community."
    confirmLabel="Unpublish"
    cancelLabel="Cancel"
    variant="danger"
    onConfirm={confirmUnpublish}
    onCancel={closeUnpublishConfirm}
  />

  <ConfirmModal
    open={showRemoveConfirm}
    title="Remove from My decks"
    message="Remove this deck from My decks? You can add it again from Community anytime."
    confirmLabel="Remove"
    cancelLabel="Cancel"
    variant="danger"
    onConfirm={confirmRemoveFromMyDecks}
    onCancel={closeRemoveConfirm}
  />

  {#if showUpdateModal}
    <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
    <div
      class="update-modal-backdrop"
      role="dialog"
      aria-modal="true"
      aria-labelledby="update-modal-title"
      tabindex="-1"
      onclick={(e) => e.target === e.currentTarget && closeUpdateModal()}
      onkeydown={(e) => e.key === 'Escape' && closeUpdateModal()}
    >
      <div
        class="update-modal"
        role="document"
        tabindex="-1"
        onclick={(e) => e.stopPropagation()}
        onkeydown={(e) => e.key === 'Escape' && closeUpdateModal()}
      >
        <h2 id="update-modal-title" class="update-modal-title">Update from Community</h2>
        {#if updateLoading}
          <p class="update-modal-loading">Loading changes…</p>
        {:else if updateError}
          <p class="update-modal-error">{updateError}</p>
        {:else if updatePreview}
          <p class="update-modal-intro">
            <strong>{updateDeck?.title ?? 'This deck'}</strong> has a newer version (v{updatePreview.source?.version ?? 1}) available.
          </p>
          <ul class="update-modal-changes">
            {#each updatePreview.changes as change}
              <li>{change}</li>
            {/each}
          </ul>
          <p class="update-modal-warn">Your copy will be replaced with the current version. This cannot be undone.</p>
        {/if}
        <div class="update-modal-actions">
          <button type="button" class="btn btn-secondary" onclick={closeUpdateModal} disabled={updateApplying}>
            Reject
          </button>
          <button
            type="button"
            class="btn btn-primary"
            onclick={confirmSourceUpdate}
            disabled={updateApplying || updateLoading || !!updateError}
          >
            {updateApplying ? 'Updating…' : 'Confirm update'}
          </button>
        </div>
      </div>
    </div>
  {/if}
</div>

<style>
  .page {
    padding: 1.5rem;
    max-width: 1200px;
    margin: 0 auto;
  }

  .page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.5rem;
  }

  .page-header h1 {
    margin: 0;
    font-size: 1.5rem;
    font-weight: 600;
    color: var(--text-primary, #f0f0f0);
  }

  .auth-required,
  .muted,
  .error {
    margin: 0;
    color: var(--text-muted, #a0a0a0);
  }

  .error {
    color: #ef4444;
  }

  .deck-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 1.25rem;
  }

  .deck-card {
    margin: 0;
  }

  .deck-card-inner {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 140px;
    padding: 1.25rem;
    background: var(--card-bg, #1a1a1a);
    border: 1px solid var(--border, #333);
    border-radius: 12px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
    cursor: pointer;
    transition: border-color 0.15s, box-shadow 0.15s;
  }

  .deck-card-inner:hover {
    border-color: var(--border-hover, #444);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
  }

  .deck-card-inner:focus {
    outline: 2px solid var(--accent, #3b82f6);
    outline-offset: 2px;
  }

  .deck-title {
    margin: 0 0 0.25rem 0;
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--text-primary, #f0f0f0);
  }

  .deck-description {
    margin: 0 0 0.5rem 0;
    font-size: 0.9rem;
    color: var(--text-muted, #a0a0a0);
    line-height: 1.4;
    flex: 1;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  .deck-meta {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.85rem;
    color: var(--text-muted, #a0a0a0);
    padding-top: 0.25rem;
  }

  .deck-rating {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.9rem;
    color: var(--text-muted, #a0a0a0);
    margin-bottom: 0.25rem;
    margin-top: auto;
    border: none;
    background: transparent;
    padding: 0;
    cursor: default;
    font: inherit;
  }

  button.deck-rating {
    cursor: pointer;
    text-align: left;
  }

  .deck-rating.clickable {
    cursor: pointer;
  }

  .deck-rating.clickable:hover {
    color: #eab308;
  }

  .deck-rating .stars {
    color: #eab308;
    letter-spacing: 0.05em;
  }

  .deck-rating .rating-count {
    font-size: 0.8rem;
    color: var(--text-muted, #888);
  }

  .deck-card-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    flex-shrink: 0;
    margin-top: 0.75rem;
  }

  .btn-icon-update {
    position: relative;
    color: var(--accent, #3b82f6);
  }

  .btn-icon-update:hover {
    color: #60a5fa;
  }

  .update-icon-wrap {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .update-badge {
    position: absolute;
    top: -6px;
    right: -6px;
    width: 22px;
    height: 22px;
    font-size: 0.8rem;
    font-weight: 700;
    color: #fff;
    background: #dc2626;
    border: 2px solid var(--card-bg, #1a1a1a);
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
    line-height: 1;
  }

  .update-modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 100;
    background: rgba(0, 0, 0, 0.6);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
  }

  .update-modal {
    background: var(--card-bg, #1a1a1a);
    border: 1px solid var(--border, #333);
    border-radius: 12px;
    max-width: 420px;
    width: 100%;
    padding: 1.5rem;
  }

  .update-modal-title {
    margin: 0 0 1rem 0;
    font-size: 1.2rem;
    font-weight: 600;
    color: var(--text-primary, #f0f0f0);
  }

  .update-modal-loading,
  .update-modal-error {
    margin: 0 0 1rem 0;
    font-size: 0.95rem;
  }

  .update-modal-error {
    color: #ef4444;
  }

  .update-modal-intro {
    margin: 0 0 0.75rem 0;
    font-size: 0.95rem;
    color: var(--text-muted, #a0a0a0);
  }

  .update-modal-changes {
    margin: 0 0 1rem 0;
    padding-left: 1.25rem;
    font-size: 0.9rem;
    color: var(--text-primary, #f0f0f0);
  }

  .update-modal-changes li {
    margin-bottom: 0.25rem;
  }

  .update-modal-warn {
    margin: 0 0 1rem 0;
    font-size: 0.85rem;
    color: var(--text-muted, #a0a0a0);
  }

  .update-modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
  }

  .btn-secondary {
    background: transparent;
  }

  .btn {
    padding: 0.5rem 1rem;
    font-size: 0.9rem;
    font-weight: 500;
    border: 1px solid var(--border, #333);
    border-radius: 6px;
    background: var(--card-bg, #1e1e1e);
    color: var(--text-primary, #f0f0f0);
    cursor: pointer;
  }

  .btn:hover {
    background: var(--hover-bg, #2a2a2a);
  }

  .btn-primary {
    background: var(--accent, #3b82f6);
    border-color: var(--accent, #3b82f6);
  }

  .btn-primary:hover {
    background: #2563eb;
  }

  .btn-small {
    padding: 0.35rem 0.75rem;
    font-size: 0.85rem;
  }

  .btn-published {
    background: rgba(34, 197, 94, 0.2);
    border-color: #22c55e;
    color: #22c55e;
  }

  .btn-published:hover:not(:disabled) {
    background: rgba(34, 197, 94, 0.3);
  }

  .btn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.35rem;
    min-width: 2rem;
  }

  .btn-icon svg {
    display: block;
  }

  .btn-icon-danger {
    color: var(--text-muted, #a0a0a0);
  }

  .btn-icon-danger:hover {
    color: #ef4444;
  }
</style>
