<script>
  import { onMount } from 'svelte';
  import HeaderBar from './components/HeaderBar.svelte';
  import SidebarTabs from './components/SidebarTabs.svelte';
  import TicketsPanel from './components/TicketsPanel.svelte';
  import MailPanel from './components/MailPanel.svelte';
  import DocsPanel from './components/DocsPanel.svelte';
  import VmsPanel from './components/VmsPanel.svelte';
  import ProfilePanel from './components/ProfilePanel.svelte';
  import { api } from './lib/api.js';
  import DebugPanel from './components/DebugPanel.svelte';

  const showDebug = new URLSearchParams(window.location.search).has('debug');
  let activeTab = 'tickets';
  let state = null;
  let tickets = [];
  let selectedTicket = null;
  let mail = [];
  let selectedMail = null;
  let docs = [];
  let selectedDoc = null;
  let vms = [];
  let connection = 'offline';
  let loading = true;
  let busy = false;
  let error = '';
  let alerts = [];
  let playerPortrait = 'player-silhouette';
  $: unreadMailCount = mail.filter((item) => !item.read).length;

  function syncSelectedRecord(collection, selected, setter) {
    if (!selected) {
      return;
    }

    const match = collection.find((item) => item.id === selected.id);
    if (!match) {
      setter(null);
    }
  }

  function attachmentToDocId(attachment) {
    return String(attachment ?? '')
      .replace(/^docs\//, '')
      .replace(/\.json$/, '');
  }

  async function refreshCore() {
    const [nextState, nextTickets, nextMail, nextDocs, nextVms] = await Promise.all([
      api.getState(),
      api.getTickets(),
      api.getMail(),
      api.getDocs(),
      api.getVms()
    ]);

    state = nextState;
    tickets = nextTickets;
    mail = nextMail;
    docs = nextDocs;
    vms = nextVms;

    if (!selectedTicket && tickets[0]) {
      await selectTicket(tickets[0].id);
    } else {
      syncSelectedRecord(tickets, selectedTicket, (value) => selectedTicket = value);
    }

    if (!selectedDoc) {
      const firstUnlocked = docs.find((doc) => !doc.locked);
      if (firstUnlocked) {
        await selectDoc(firstUnlocked.id);
      }
    } else {
      syncSelectedRecord(docs, selectedDoc, (value) => selectedDoc = value);
    }

    if (selectedMail) {
      const stillExists = mail.find((item) => item.id === selectedMail.id);
      if (stillExists) {
        selectedMail = await api.getMailById(selectedMail.id);
      } else {
        selectedMail = null;
      }
    }
  }

  async function selectTicket(id) {
    selectedTicket = await api.getTicket(id);
  }

  async function selectMail(id) {
    const detail = await api.getMailById(id);
    if (!detail.read) {
      await api.markMailRead(id);
      mail = mail.map((item) => item.id === id ? { ...item, read: true } : item);
      selectedMail = { ...detail, read: true };
      return;
    }

    selectedMail = detail;
  }

  async function selectDoc(id) {
    selectedDoc = await api.getDoc(id);
  }

  async function completeTicket(event) {
    try {
      busy = true;
      error = '';
      const result = await api.completeTicket(event.detail);
      if (!result?.passed) {
        const failureText = Array.isArray(result?.failures) && result.failures.length > 0
          ? result.failures.join('\n')
          : result?.reason ?? 'Validation failed';
        error = `Ticket could not be completed.\n${failureText}`;
        return;
      }

      await refreshCore();
      if (tickets[0]) {
        await selectTicket(tickets[0].id);
      }
    } catch (nextError) {
      error = nextError.message;
    } finally {
      busy = false;
    }
  }

  async function replyToMail(event) {
    const { id, choice } = event.detail;
    try {
      busy = true;
      error = '';
      await api.replyMail(id, choice);
      await refreshCore();
      await selectMail(id);
    } catch (nextError) {
      error = nextError.message;
    } finally {
      busy = false;
    }
  }

  async function openAttachment(event) {
    const docId = attachmentToDocId(event.detail);
    activeTab = 'docs';
    try {
      await selectDoc(docId);
    } catch (nextError) {
      error = nextError.message;
    }
  }

  function connectSocket() {
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    const socket = new WebSocket(`${protocol}//${window.location.host}`);

    socket.addEventListener('open', () => {
      connection = 'connected';
    });

    socket.addEventListener('close', () => {
      connection = 'offline';
      window.setTimeout(connectSocket, 1500);
    });

    socket.addEventListener('message', async (event) => {
      try {
        const message = JSON.parse(event.data);
        if (message.type === 'shift:tick') {
          state = {
            ...(state ?? {}),
            shift: message.payload
          };
          return;
        }

        if (message.type === 'incident:alert') {
          alerts = [message.payload, ...alerts].slice(0, 3);
        }

        if (['trust:changed', 'progression:changed', 'mail:new', 'quest:completed', 'quest:activated', 'incident:alert', 'shift:ended', 'certification:awarded'].includes(message.type)) {
          await refreshCore();
        }
      } catch {
        // Ignore malformed socket events in the HUD.
      }
    });
  }

  async function savePortrait(portrait) {
    playerPortrait = portrait;
    try {
      await api.setProfile(portrait);
    } catch {
      // portrait is already set locally; persist failure is non-fatal
    }
  }

  onMount(async () => {
    try {
      await api.ensureSession();
      const profile = await api.getProfile();
      playerPortrait = profile.portrait ?? 'player-silhouette';
      await refreshCore();
      connectSocket();
    } catch (nextError) {
      error = nextError.message;
    } finally {
      loading = false;
    }
  });
</script>

<svelte:head>
  <title>Sysadmin Chronicles HUD</title>
</svelte:head>

{#if loading}
  <main class="shell centered">
    <p>Bringing the desk online…</p>
  </main>
{:else}
  <main class="shell">
    <HeaderBar {state} {connection} {playerPortrait} />

    {#if error}
      <div class="error">{error}</div>
    {/if}

    {#if alerts.length > 0}
      <section class="alerts">
        {#each alerts as alert}
          <article class={`alert ${alert.severity ?? 'warning'}`}>
            <strong>{alert.subject}</strong>
            <p>{alert.message}</p>
          </article>
        {/each}
      </section>
    {/if}

    <section class="workspace">
      <SidebarTabs
        active={activeTab}
        unreadMailCount={unreadMailCount}
        on:change={(event) => activeTab = event.detail}
      />

      <div class="content">
        {#if activeTab === 'tickets'}
          <TicketsPanel
            {tickets}
            {selectedTicket}
            {busy}
            on:select={(event) => selectTicket(event.detail)}
            on:complete={completeTicket}
          />
        {:else if activeTab === 'mail'}
          <MailPanel
            {mail}
            {selectedMail}
            {busy}
            on:select={(event) => selectMail(event.detail)}
            on:reply={replyToMail}
            on:attachment={openAttachment}
          />
        {:else if activeTab === 'docs'}
          <DocsPanel
            {docs}
            {selectedDoc}
            on:select={(event) => selectDoc(event.detail)}
          />
        {:else if activeTab === 'vms'}
          <VmsPanel {vms} />
        {:else if activeTab === 'profile'}
          <ProfilePanel
            certifications={state?.certifications ?? []}
            shiftHistory={state?.shiftHistory ?? []}
            currentShiftStats={state?.currentShiftStats ?? null}
            {playerPortrait}
            on:portrait={(event) => savePortrait(event.detail)}
          />
        {/if}
      </div>
    </section>
  {#if import.meta.env.DEV && showDebug}<DebugPanel />{/if}
  </main>
{/if}

<style>
  .shell {
    max-width: 1440px;
    margin: 0 auto;
    padding: 2rem;
  }

  .centered {
    display: grid;
    place-items: center;
    min-height: 100vh;
  }

  .workspace {
    display: grid;
    grid-template-columns: 220px minmax(0, 1fr);
    gap: 1rem;
  }

  .alerts {
    display: grid;
    gap: 0.75rem;
    margin-bottom: 1rem;
  }

  .alert {
    border-radius: 16px;
    border: 1px solid var(--border);
    background: var(--panel);
    box-shadow: var(--shadow);
    padding: 0.9rem 1rem;
  }

  .alert.warning {
    border-color: rgba(213, 166, 75, 0.35);
  }

  .alert.error,
  .alert.critical {
    border-color: rgba(200, 101, 101, 0.4);
  }

  .alert strong {
    display: block;
    margin-bottom: 0.3rem;
  }

  .alert p {
    margin: 0;
    color: var(--text-muted);
  }

  .content {
    min-height: 70vh;
  }

  .error {
    margin-bottom: 1rem;
    padding: 0.9rem 1rem;
    border: 1px solid rgba(200, 101, 101, 0.35);
    border-radius: 16px;
    background: rgba(200, 101, 101, 0.12);
    color: #ffddd8;
  }

  @media (max-width: 960px) {
    .shell {
      padding: 1rem;
    }

    .workspace {
      grid-template-columns: 1fr;
    }
  }
</style>
