'use client';

import {useState} from 'react';
import {VStack} from '@astryxdesign/core/Layout';
import {Grid} from '@astryxdesign/core/Grid';
import {Button} from '@astryxdesign/core/Button';
import {Icon} from '@astryxdesign/core/Icon';
import {PageHeader} from '@/components/primitives/PageHeader';
import {ScopeControls} from '@/components/scope/ScopeControls';
import {ICONS} from '@/lib/icons';
import {ChartCard} from '@/components/charts/ChartCard';
import {AreaChartView} from '@/components/charts/AreaChartView';
import {LineChartView} from '@/components/charts/LineChartView';
import {BarChartView} from '@/components/charts/BarChartView';
import {HeatmapGrid} from '@/components/charts/HeatmapGrid';
import {KpiRow} from '@/features/dashboard/KpiRow';
import {ActivityTimeline} from '@/features/dashboard/ActivityTimeline';
import {RewardUsageChart} from '@/features/dashboard/RewardUsageChart';
import {StoreComparisonPanel} from '@/features/dashboard/StoreComparison';
import {PerformancePanel} from '@/features/dashboard/PerformancePanel';
import {useResource} from '@/lib/api/useResource';
import {endpoints} from '@/lib/api/client';
import {useWorkspace} from '@/components/shell/WorkspaceProvider';
import {storeName} from '@/lib/mock/stores';
import type {Granularity} from '@/lib/api/contracts';
import {
  formatCompact,
  formatDayLabel,
  formatInrCompact,
  formatPct,
} from '@/lib/format';

/**
 * An analytics workspace. Charts are the subject, not evidence for a to-do list.
 *
 * The page reads top-down as one narrowing question: headline numbers → the two
 * trends that drive them → the conversion story behind those → when and on what
 * it happens → the period rollup → which store → what just happened.
 *
 * Operational widgets — quick actions, tasks, the AI briefing, top store/reward,
 * staff status — deliberately do NOT live here. The briefing endpoint they were
 * built on is still live and feeds the Copilot's AI tab, which is where that
 * class of content belongs: a panel you open to be told what to do, beside a
 * dashboard you read to work it out yourself.
 *
 * Recent activity keeps its compact form — six rows in a fixed box, full history
 * on /activity. The uncapped version reached 784px, taller than any chart on the
 * page, which is an operational log outweighing the analytics it sits among.
 *
 * Every panel is scoped by the same {storeId, range} from WorkspaceProvider, set
 * from this page's header. `series` is fetched once and shared by the four
 * charts drawn from it, so they cannot disagree.
 */

/**
 * Derived from the SERVER's clock, carried on the response meta.
 *
 * Calling Date.now() during render is impure and disagrees between the SSR and
 * hydration passes. Before meta lands there is no instant to reason about, so
 * the greeting is the time-independent one; both strings are a single line, so
 * the swap costs no layout shift. getHours() resolves the server's instant in
 * the viewer's zone, which is the hour the merchant is actually living in.
 */
function greetingFor(generatedAt?: string): string {
  if (!generatedAt) return 'Welcome back';
  const hour = new Date(generatedAt).getHours();
  if (hour < 12) return 'Good morning';
  if (hour < 17) return 'Good afternoon';
  return 'Good evening';
}

export default function DashboardPage() {
  const {storeId, range} = useWorkspace();
  const [granularity, setGranularity] = useState<Granularity>('weekly');
  // On by default: store comparison has always been part of the all-stores
  // dashboard, so Compare starts pressed and switches the panel off, rather
  // than hiding a panel that used to be there until someone finds the button.
  const [isComparing, setIsComparing] = useState(true);

  const scope = {range, storeId};

  const kpis = useResource(endpoints.dashboardKpis(scope));
  const series = useResource(endpoints.dashboardTimeseries(scope));
  const peak = useResource(endpoints.dashboardPeakHours(scope));
  const activity = useResource(endpoints.dashboardActivity(scope));
  const rewards = useResource(endpoints.dashboardRewardUsage(scope));
  const comparison = useResource(endpoints.dashboardStoreComparison(scope));

  const isAllStores = storeId === 'all';
  const scopeLabel = isAllStores ? 'all stores' : storeName(storeId);

  return (
    <VStack gap={5}>
      {/* 1 + 2 — greeting, title, and the store / period / compare filters. */}
      <PageHeader
        eyebrow={greetingFor(kpis.meta?.generatedAt)}
        title="Dashboard"
        description={`Business performance across ${scopeLabel}.`}
        controls={
          <>
            <ScopeControls />
            <Button
              size="sm"
              // Pressed state is the raised gray of `primary` in this theme —
              // a toggle needs a visible on-state, and it must not be colour.
              variant={isComparing ? 'primary' : 'secondary'}
              label="Compare"
              icon={<Icon icon={ICONS.compare} size="sm" />}
              aria-pressed={isComparing}
              isDisabled={!isAllStores}
              // With a tooltip present, Button uses aria-disabled rather than
              // the native attribute, so the reason stays reachable by keyboard
              // instead of the control just going dead.
              tooltip={
                isAllStores
                  ? undefined
                  : 'Comparing stores needs the All stores scope'
              }
              onClick={() => setIsComparing((v) => !v)}
            />
          </>
        }
      />

      {/* 3 — headline numbers. */}
      <KpiRow resource={kpis} />

      {/* 4 — primary analytics: the two series everything else explains. */}
      <Grid columns={{minWidth: 360, max: 2, repeat: 'fit'}} gap={4}>
        <ChartCard title="Footfall" subtitle="Visitors per day" resource={series}>
          {(d) => (
            <AreaChartView
              data={d}
              xKey="t"
              xFormat={formatDayLabel}
              yFormat={formatCompact}
              series={[{key: 'visitors', label: 'Visitors'}]}
            />
          )}
        </ChartCard>

        <ChartCard title="Revenue" subtitle="Daily takings" resource={series}>
          {(d) => (
            <BarChartView
              data={d}
              xKey="t"
              xFormat={formatDayLabel}
              yFormat={formatInrCompact}
              series={[{key: 'revenue', label: 'Revenue'}]}
            />
          )}
        </ChartCard>
      </Grid>

      {/* 5 — secondary analytics: the conversion story, in two readings. */}
      <Grid columns={{minWidth: 360, max: 2, repeat: 'fit'}} gap={4}>
        <ChartCard
          title="Visitors vs purchases"
          subtitle="The gap is the conversion opportunity"
          resource={series}
        >
          {(d) => (
            <LineChartView
              data={d}
              xKey="t"
              xFormat={formatDayLabel}
              yFormat={formatCompact}
              series={[
                {key: 'visitors', label: 'Visitors'},
                {key: 'purchases', label: 'Purchases'},
              ]}
            />
          )}
        </ChartCard>

        <ChartCard
          title="Conversion"
          subtitle="Share of visitors who bought"
          resource={series}
        >
          {(d) => (
            <LineChartView
              data={d}
              xKey="t"
              xFormat={formatDayLabel}
              yFormat={(v) => formatPct(v, 0)}
              series={[{key: 'conversion', label: 'Conversion'}]}
              // The only semantic colour on this chart: above the benchmark is
              // good, below is not, and that is what the tint communicates.
              reference={{y: 22, label: 'Network benchmark', tone: 'positive'}}
            />
          )}
        </ChartCard>
      </Grid>

      {/* 6 — operational analytics: when traffic lands, what it redeems. */}
      <Grid columns={{minWidth: 360, max: 2, repeat: 'fit'}} gap={4}>
        <ChartCard
          title="Peak hours"
          subtitle="Where the week's footfall actually lands"
          resource={peak}
          height={200}
        >
          {(d) => <HeatmapGrid data={d} />}
        </ChartCard>

        <RewardUsageChart resource={rewards} />
      </Grid>

      {/* 7 — period rollup. */}
      <PerformancePanel
        scope={scope}
        granularity={granularity}
        onGranularityChange={setGranularity}
      />

      {/* 8 — comparing stores is meaningless when scoped to one of them, which
             is why Compare is disabled rather than merely off in that case. */}
      {isAllStores && isComparing ? (
        <StoreComparisonPanel resource={comparison} />
      ) : null}

      {/* 9 — bounded feed: six rows, fixed box, full history on /activity. */}
      <ActivityTimeline
        resource={activity}
        subtitle="Latest events across the selected store and period"
        limit={6}
        height={285}
        viewAllHref="/activity"
      />
    </VStack>
  );
}
