<script lang="ts">
  import { onMount } from 'svelte';
  import { page } from '$app/state';
  import TaskSlideOver from '$lib/components/dashboard/TaskSlideOver.svelte';

  interface QuickTask {
    id: string;
    title: string;
    startDate?: string;
    dueDate?: string;
    isAllDay?: boolean;
    projectId: string;
    _projectName: string;
    _projectId: string;
  }

  const userName = $derived((page as any).data?.user?.display_name || 'there');

  let loading = $state(true);
  let taskPanelOpen = $state(false);
  let taskToday = $state<QuickTask[]>([]);
  let taskOverdue = $state<QuickTask[]>([]);
  let inventoryIssueCount = $state(0);
  let inventoryReviewCount = $state(0);
  let budgetUncatCount = $state(0);
  let budgetSpending = $state(0);
  let budgetIncome = $state(0);
  let readerUnread = $state(0);
  let readerStarred = $state(0);
  let fitnessCalLogged = $state(0);
  let fitnessCalGoal = $state(2000);
  let fitnessProtein = $state(0);
  let fitnessProteinGoal = $state(150);
  let fitnessCarbs = $state(0);
  let fitnessCarbsGoal = $state(200);
  let fitnessFat = $state(0);
  let fitnessFatGoal = $state(65);

  function getGreeting(): string {
    const h = new Date().getHours();
    if (h < 12) return 'Good morning';
    if (h < 17) return 'Good afternoon';
    return 'Good evening';
  }

  function getDateString(): string {
    return new Date().toLocaleDateString('en-US', {
      weekday: 'long',
      month: 'long',
      day: 'numeric'
    });
  }

  function formatMoney(value: number): string {
    return '$' + Math.abs(value || 0).toLocaleString('en-US');
  }

  function formatSignedMoney(value: number): string {
    const abs = '$' + Math.abs(value || 0).toLocaleString('en-US');
    return value < 0 ? `-${abs}` : abs;
  }

  function formatTaskTime(t: QuickTask): string {
    const d = t.startDate || t.dueDate;
    if (!d || t.isAllDay) return '';
    try {
      const date = new Date(d);
      const h = date.getHours();
      const m = date.getMinutes();
      if (h === 0 && m === 0) return '';
      const ampm = h >= 12 ? 'PM' : 'AM';
      const hour = h % 12 || 12;
      return m > 0 ? `${hour}:${String(m).padStart(2, '0')} ${ampm}` : `${hour} ${ampm}`;
    } catch {
      return '';
    }
  }

  const taskCount = $derived(taskToday.length + taskOverdue.length);
  const fitPercent = $derived(fitnessCalGoal > 0 ? Math.min(100, Math.round((fitnessCalLogged / fitnessCalGoal) * 100)) : 0);
  const fitnessRemaining = $derived(Math.max(0, fitnessCalGoal - fitnessCalLogged));
  const nextTask = $derived(taskOverdue[0] || taskToday[0] || null);
  const spendMagnitude = $derived(Math.abs(budgetSpending || 0));
  const netCash = $derived(budgetIncome - spendMagnitude);
  const spendVsIncomePercent = $derived(
    budgetIncome > 0 ? Math.min(100, Math.round((spendMagnitude / budgetIncome) * 100)) : 0
  );

  const topSignals = $derived([
    {
      label: 'Open tasks',
      value: String(taskCount),
      note: taskOverdue.length > 0 ? `${taskOverdue.length} overdue` : taskToday[0] ? `${taskToday.length} scheduled today` : 'Nothing urgent'
    },
    {
      label: 'Inventory pressure',
      value: `${inventoryIssueCount + inventoryReviewCount}`,
      note: `${inventoryIssueCount} issues · ${inventoryReviewCount} review`
    },
    {
      label: 'Budget open',
      value: `${budgetUncatCount}`,
      note: `${formatMoney(budgetSpending)} spent this month`
    },
    {
      label: 'Reader queue',
      value: `${readerUnread}`,
      note: `${readerStarred} starred reads`
    }
  ]);

  async function loadDashboard() {
    loading = true;
    const now = new Date();
    const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;

    try {
      const [tasksRes, invRes, budgetRes, uncatRes, fitTotalsRes, fitGoalsRes, readerCountersRes, readerStarredRes] = await Promise.all([
        fetch('/api/tasks/today', { credentials: 'include' }),
        fetch('/api/inventory/summary', { credentials: 'include' }),
        fetch('/api/budget/summary', { credentials: 'include' }),
        fetch('/api/budget/uncategorized-count', { credentials: 'include' }),
        fetch(`/api/fitness/entries/totals?date=${today}`, { credentials: 'include' }),
        fetch(`/api/fitness/goals/for-date?date=${today}`, { credentials: 'include' }),
        fetch('/api/reader/feeds/counters', { credentials: 'include' }),
        fetch('/api/reader/entries?starred=true&limit=1', { credentials: 'include' })
      ]);

      if (tasksRes.ok) {
        const t = await tasksRes.json();
        taskToday = t.today || [];
        taskOverdue = t.overdue || [];
      }

      if (invRes.ok) {
        const data = await invRes.json();
        inventoryIssueCount = data.issueCount || 0;
        inventoryReviewCount = data.reviewCount || 0;
      }

      if (budgetRes.ok) {
        const data = await budgetRes.json();
        budgetSpending = data.spendingDollars || 0;
        budgetIncome = data.incomeDollars || 0;
      }

      if (uncatRes.ok) {
        const data = await uncatRes.json();
        budgetUncatCount = data.count || 0;
      }

      if (fitTotalsRes.ok) {
        const data = await fitTotalsRes.json();
        fitnessCalLogged = Math.round(data.total_calories || 0);
        fitnessProtein = Math.round(data.total_protein || 0);
        fitnessCarbs = Math.round(data.total_carbs || 0);
        fitnessFat = Math.round(data.total_fat || 0);
      }

      if (fitGoalsRes.ok) {
        const data = await fitGoalsRes.json();
        fitnessCalGoal = data.calories || 2000;
        fitnessProteinGoal = data.protein || 150;
        fitnessCarbsGoal = data.carbs || 200;
        fitnessFatGoal = data.fat || 65;
      }

      if (readerCountersRes.ok) {
        const data = await readerCountersRes.json();
        readerUnread = Object.values(data.unreads || {}).reduce((sum: number, value: any) => sum + (value as number), 0);
      }

      if (readerStarredRes.ok) {
        const data = await readerStarredRes.json();
        readerStarred = data.total || 0;
      }
    } catch {
      // Keep partial dashboard rendering if one source fails.
    }

    loading = false;
  }

  onMount(loadDashboard);
</script>

<div class="dashboard-page">
  <TaskSlideOver bind:open={taskPanelOpen} onclose={() => { taskPanelOpen = false; loadDashboard(); }} />

  <div class="dashboard-grid">
    <section class="hero-panel panel intro-sequence">
      <div class="hero-copy">
        <div class="panel-kicker">Today at a glance</div>
        <h1>{getGreeting()}, {userName}.</h1>
        <p>Scan the work that actually needs attention, then drop into the right app without bouncing through repeated modules.</p>
      </div>

      <div class="hero-signals">
        {#each topSignals as item, index}
          <div class="signal-line reveal-item" style={`--delay:${index * 80}ms`}>
            <div>
              <div class="signal-label">{item.label}</div>
              <div class="signal-note">{item.note}</div>
            </div>
            <div class="signal-value">{loading ? '…' : item.value}</div>
          </div>
        {/each}
      </div>
    </section>

    <section class="agenda-panel panel intro-sequence">
      <div class="panel-head">
        <div>
          <div class="panel-kicker">Daily sequence</div>
          <h2>Agenda</h2>
        </div>
        <button class="inline-link" onclick={() => taskPanelOpen = true}>Open tasks</button>
      </div>

      <div class="agenda-list">
        {#if loading}
          {#each [1, 2, 3, 4] as _}
            <div class="agenda-row skeleton-row"></div>
          {/each}
        {:else if taskCount === 0}
          <div class="agenda-empty">No tasks are due today.</div>
        {:else}
          {#each [...taskOverdue.slice(0, 2), ...taskToday.slice(0, 3)].slice(0, 4) as task}
            <button class="agenda-row" onclick={() => taskPanelOpen = true}>
              <div class="agenda-time">{taskOverdue.find((t) => t.id === task.id) ? 'Overdue' : formatTaskTime(task) || 'Today'}</div>
              <div class="agenda-main">
                <div class="agenda-title">{task.title}</div>
                <div class="agenda-tag">{task._projectName}</div>
              </div>
            </button>
          {/each}
        {/if}
      </div>
    </section>

    <section class="main-column intro-sequence">
      <div class="panel budget-panel">
        <div class="panel-head">
          <div>
            <div class="panel-kicker">Budget state</div>
            <h2>Cash movement</h2>
          </div>
          <a href="/budget" class="inline-link">Open budget</a>
        </div>

        <div class="budget-figure">{formatMoney(spendMagnitude)}</div>
        <div class="budget-copy">Spent this month with {budgetUncatCount} uncategorized transactions still open for review.</div>

        <div class="budget-meter">
          <div class="budget-meter-top">
            <span>Spend vs income</span>
            <strong>{spendVsIncomePercent}%</strong>
          </div>
          <div class="budget-bar"><span style={`width:${spendVsIncomePercent}%`}></span></div>
        </div>

        <div class="budget-breakdown">
          <div>
            <div class="mini-label">Income</div>
            <div class="mini-value">{formatMoney(budgetIncome)}</div>
          </div>
          <div>
            <div class="mini-label">Uncategorized</div>
            <div class="mini-value">{budgetUncatCount}</div>
          </div>
          <div>
            <div class="mini-label">Net</div>
            <div class="mini-value">{formatSignedMoney(netCash)}</div>
          </div>
        </div>
      </div>
    </section>

    <section class="side-column intro-sequence">
      <div class="panel section-panel">
        <div class="panel-head">
          <div>
            <div class="panel-kicker">Calorie target</div>
            <h2>Calories</h2>
          </div>
          <a href="/fitness" class="inline-link">Open fitness</a>
        </div>

        <div class="nutrition-summary calories-only">
          <div class="calorie-block">
            <div class="calorie-head">
              <strong>{fitnessCalLogged.toLocaleString()} / {fitnessCalGoal.toLocaleString()}</strong>
              <span>{fitnessRemaining.toLocaleString()} left</span>
            </div>
            <div class="macro-bar calories"><span style={`width:${fitPercent}%`}></span></div>
            <div class="calorie-note">{fitPercent}% of target logged today</div>
          </div>
        </div>
      </div>
    </section>
  </div>
</div>

<style>
  .dashboard-page {
    min-height: calc(100vh - 56px);
  }

  .dashboard-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.45fr) minmax(320px, 0.92fr);
    gap: 18px;
    padding: 24px 24px 120px;
    max-width: 1460px;
    margin: 0 auto;
  }

  .panel {
    background: rgba(255, 252, 248, 0.82);
    border: 1px solid rgba(35, 26, 17, 0.12);
    backdrop-filter: blur(14px);
    box-shadow: 0 18px 40px rgba(35, 24, 15, 0.05);
  }

  .hero-panel,
  .agenda-panel,
  .section-panel,
  .budget-panel {
    border-radius: 28px;
  }

  .hero-panel {
    padding: 24px;
    min-height: 330px;
    display: grid;
    align-content: space-between;
    background:
      linear-gradient(145deg, rgba(255, 250, 244, 0.9), rgba(246, 233, 220, 0.58)),
      radial-gradient(circle at 86% 14%, rgba(179, 92, 50, 0.18), transparent 28%);
  }

  .hero-copy h1 {
    margin: 8px 0 12px;
    max-width: 10ch;
    font-size: clamp(2.25rem, 3.9vw, 3.8rem);
    line-height: 0.92;
    letter-spacing: -0.07em;
    color: #1e1812;
  }

  .hero-copy p,
  .signal-note,
  .budget-copy,
  .focus-meta {
    color: #5c5247;
    line-height: 1.6;
  }

  .panel-kicker,
  .signal-label,
  .strip-label,
  .mini-label,
  .agenda-tag {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: #7b6d5f;
    font-weight: 700;
  }

  .hero-signals {
    display: grid;
    gap: 14px;
  }

  .signal-line {
    display: flex;
    align-items: end;
    justify-content: space-between;
    gap: 14px;
    padding-top: 16px;
    border-top: 1px solid rgba(35, 26, 17, 0.12);
  }

  .signal-value {
    font-size: clamp(1.7rem, 3vw, 2.45rem);
    font-weight: 600;
    letter-spacing: -0.05em;
    color: #1e1812;
  }

  .agenda-panel,
  .section-panel,
  .budget-panel {
    padding: 20px 22px;
  }

  .panel-head {
    display: flex;
    justify-content: space-between;
    align-items: end;
    gap: 12px;
    margin-bottom: 16px;
  }

  .panel-head h2 {
    margin: 4px 0 0;
    font-size: 1.45rem;
    font-weight: 650;
    line-height: 1;
    letter-spacing: -0.05em;
    color: #1e1812;
  }

  .inline-link,
  .focus-link {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    border: none;
    background: none;
    padding: 0;
    font-size: 13px;
    font-weight: 600;
    color: #2f6a52;
    cursor: pointer;
    font-family: var(--font);
  }

  .agenda-list {
    display: grid;
    gap: 14px;
  }

  .agenda-row {
    display: grid;
    grid-template-columns: 82px minmax(0, 1fr);
    gap: 12px;
    align-items: start;
    text-align: left;
    padding-top: 12px;
    border-top: 1px solid rgba(35, 26, 17, 0.11);
    background: none;
    border-left: none;
    border-right: none;
    border-bottom: none;
    cursor: pointer;
    font-family: var(--font);
    transition: color 160ms ease, transform 160ms ease;
  }

  .agenda-row:hover {
    transform: translateX(2px);
  }

  .agenda-time {
    font-size: 1rem;
    color: #4e443a;
    letter-spacing: -0.03em;
  }

  .agenda-title {
    font-size: 1.1rem;
    font-weight: 600;
    letter-spacing: -0.04em;
    color: #1e1812;
  }

  .agenda-main {
    display: grid;
    gap: 4px;
  }

  .agenda-empty {
    padding: 18px 0 8px;
    color: #6b6256;
  }

  .skeleton-row {
    min-height: 48px;
    opacity: 0.4;
  }

  .strip-row {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 12px;
  }

  .strip-block {
    padding: 18px 18px 20px;
    border-radius: 22px;
    background: rgba(255, 252, 248, 0.66);
    border: 1px solid rgba(35, 26, 17, 0.1);
    backdrop-filter: blur(14px);
    text-decoration: none;
    color: inherit;
    transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease;
  }

  .strip-block:hover {
    transform: translateY(-2px);
    box-shadow: 0 16px 34px rgba(35, 24, 15, 0.08);
  }

  .strip-top {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    align-items: center;
  }

  .strip-meta,
  .strip-detail {
    color: #6b6256;
    font-size: 0.92rem;
  }

  .strip-title {
    margin-top: 10px;
    font-size: 1.55rem;
    line-height: 1;
    letter-spacing: -0.05em;
    color: #1e1812;
  }

  .strip-detail {
    margin-top: 6px;
    line-height: 1.5;
  }

  .strip-bar,
  .lane-meter,
  .macro-bar {
    height: 6px;
    background: rgba(35, 26, 17, 0.08);
    border-radius: 999px;
    overflow: hidden;
  }

  .strip-bar {
    margin-top: 14px;
  }

  .strip-fill,
  .lane-meter span,
  .macro-bar span {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(90deg, #346c56 0%, #4d8f73 100%);
    transition: width 900ms cubic-bezier(0.16, 1, 0.3, 1);
  }

  .main-column {
    display: grid;
    gap: 18px;
  }

  .lane-title,
  .focus-title {
    font-size: 1.08rem;
    font-weight: 600;
    letter-spacing: -0.03em;
    color: #1e1812;
  }

  .lane-value,
  .mini-value {
    font-size: 1rem;
    font-family: var(--mono);
    color: #1e1812;
  }

  .budget-panel {
    background:
      linear-gradient(145deg, rgba(255, 251, 246, 0.96), rgba(241, 247, 243, 0.82)),
      radial-gradient(circle at 88% 14%, rgba(47, 106, 82, 0.1), transparent 28%);
  }

  .budget-figure {
    font-size: clamp(2.2rem, 4vw, 3.35rem);
    line-height: 0.92;
    letter-spacing: -0.07em;
    color: #1e1812;
    margin-bottom: 8px;
  }

  .budget-breakdown {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 14px;
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid rgba(35, 26, 17, 0.09);
  }

  .budget-meter {
    margin-top: 20px;
    display: grid;
    gap: 8px;
  }

  .budget-meter-top {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    align-items: center;
    color: #6b6256;
    font-size: 0.9rem;
  }

  .budget-meter-top strong {
    color: #1e1812;
    font-family: var(--mono);
    font-weight: 600;
  }

  .budget-bar {
    height: 10px;
    border-radius: 999px;
    background: rgba(35, 26, 17, 0.08);
    overflow: hidden;
  }

  .budget-bar span {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(90deg, #2f6a52 0%, #7db592 100%);
    transition: width 900ms cubic-bezier(0.16, 1, 0.3, 1);
  }

  .side-column {
    display: grid;
    gap: 18px;
    align-content: start;
  }

  .nutrition-summary {
    display: grid;
    gap: 14px;
  }

  .calories-only {
    min-height: 140px;
    align-content: start;
  }

  .calorie-block {
    display: grid;
    gap: 10px;
  }

  .calorie-head {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    align-items: center;
  }

  .calorie-head strong {
    color: #1e1812;
    font-size: 1.18rem;
    font-family: var(--mono);
    font-weight: 600;
  }

  .calorie-head span,
  .calorie-note {
    color: #6b6256;
    font-size: 0.92rem;
  }

  .macro-bar.calories span {
    background: linear-gradient(90deg, #346c56 0%, #4d8f73 100%);
  }

  .macro-rows {
    display: grid;
    gap: 14px;
  }

  .macro-row {
    display: grid;
    gap: 6px;
  }

  .macro-top {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    align-items: center;
    color: #6b6256;
    font-size: 0.92rem;
  }

  .macro-top strong {
    color: #1e1812;
    font-family: var(--mono);
    font-weight: 600;
  }

  .macro-bar.carbs span {
    background: linear-gradient(90deg, #c88932 0%, #dca95e 100%);
  }

  .macro-bar.fat span {
    background: linear-gradient(90deg, #8f5d42 0%, #b67c5b 100%);
  }

  .intro-sequence {
    animation: riseIn 720ms cubic-bezier(0.16, 1, 0.3, 1) both;
  }

  .intro-sequence:nth-child(1) { animation-delay: 20ms; }
  .intro-sequence:nth-child(2) { animation-delay: 90ms; }
  .intro-sequence:nth-child(3) { animation-delay: 140ms; }
  .intro-sequence:nth-child(4) { animation-delay: 190ms; }
  .intro-sequence:nth-child(5) { animation-delay: 230ms; }

  .reveal-item {
    opacity: 0;
    animation: revealLine 560ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
    animation-delay: var(--delay, 0ms);
  }

  @keyframes riseIn {
    from {
      opacity: 0;
      transform: translateY(18px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  @keyframes revealLine {
    from {
      opacity: 0;
      transform: translateY(10px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  @media (max-width: 1100px) {
    .dashboard-grid {
      grid-template-columns: 1fr;
    }

    .strip-row {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  @media (max-width: 768px) {
    .dashboard-grid {
      padding: 20px 16px 120px;
      gap: 14px;
    }

    .hero-panel,
    .agenda-panel,
    .section-panel,
    .budget-panel {
      border-radius: 24px;
      padding: 18px;
    }

    .hero-copy h1 {
      font-size: 2.6rem;
    }

    .strip-row,
    .budget-breakdown {
      grid-template-columns: 1fr;
    }

    .lane-row {
      grid-template-columns: 1fr;
    }

    .agenda-row {
      grid-template-columns: 1fr;
      gap: 4px;
    }

    .panel-head {
      align-items: start;
      flex-direction: column;
    }
  }
</style>
