'use client';

import {VStack} from '@astryxdesign/core/Layout';
import {Grid} from '@astryxdesign/core/Grid';
import {Text} from '@astryxdesign/core/Text';
import {PageHeader} from '@/shared/components/primitives/PageHeader';
import {MetricCard} from '@/shared/components/patterns/MetricCard';
import {SkeletonMetricGrid} from '@/shared/components/patterns/LoadingState';
import {AsyncBoundary} from '@/shared/components/data/AsyncBoundary';
import {ChartCard} from '@/shared/components/charts/ChartCard';
import {AreaChartView} from '@/shared/components/charts/AreaChartView';
import {LineChartView} from '@/shared/components/charts/LineChartView';
import {BarChartView} from '@/shared/components/charts/BarChartView';
import {RewardGrid} from '@/features/lyts/components/RewardGrid';
import {ExpiryAlerts} from '@/features/lyts/components/ExpiryAlerts';
import {RewardPerformanceTable} from '@/features/lyts/components/RewardPerformanceTable';
import {ActivityTimeline} from '@/features/dashboard/components/ActivityTimeline';
import {useMetricColumns} from '@/features/dashboard/components/KpiRow';
import {
  useLytsActivity,
  useRedemptions,
  useRewards,
} from '@/features/lyts/hooks/useLyts';
import {ScopeControls} from '@/shared/components/scope/ScopeControls';
import {ICONS} from '@/shared/utils/icons';
import {usageRate} from '@/features/lyts/services/lytsService';
import {
  formatCompact,
  formatDayLabel,
  formatLyt,
  formatPct,
} from '@/shared/utils/format';

/**
 * The LYT programme.
 *
 * Ordered by urgency rather than by data type: what's expiring, then the
 * headline numbers, then the catalogue, then the analysis. A merchant opening
 * this page is usually here because something needs extending or pausing.
 *
 * 1 LYT = ₹1, so "outstanding" figures are simultaneously a count and a
 * rupee liability — which is why they lead.
 */
export default function LytsPage() {
  const rewards = useRewards();
  const redemptions = useRedemptions();
  const activity = useLytsActivity();

  const columns = useMetricColumns();

  // "Now" comes from the SERVER's clock, carried on every response.
  //
  // Date.now() here would be impure during render, would disagree between the
  // SSR and hydration passes, and would report the wrong countdown to anyone
  // whose device clock is off — on a panel whose entire job is telling a
  // merchant an offer expires in two days. Falls back to 0 only before the
  // first response lands, when no expiry panel is rendered anyway.
  const nowMs = rewards.meta
    ? new Date(rewards.meta.generatedAt).getTime()
    : 0;

  return (
    <VStack gap={5}>
      <PageHeader
        title="Lyts"
        description="Reward performance, redemption and outstanding LYT liability. 1 LYT = ₹1."
        controls={<ScopeControls />}
      />

      <ExpiryAlerts resource={rewards} nowMs={nowMs} />

      <AsyncBoundary
        resource={rewards}
        loading={<SkeletonMetricGrid columns={columns} />}
      >
        {(rows) => {
          const active = rows.filter(
            (r) => r.status === 'active' || r.status === 'expiring',
          );
          const claimed = rows.reduce((a, r) => a + r.claimed, 0);
          const used = rows.reduce((a, r) => a + r.used, 0);
          const outstanding = rows.reduce(
            (a, r) => a + (r.claimed - r.used) * r.costLyt,
            0,
          );
          const mostClaimed = rows.reduce((a, b) =>
            b.claimed > a.claimed ? b : a,
          );
          const leastUsed = rows.reduce((a, b) =>
            usageRate(b.claimed, b.used) < usageRate(a.claimed, a.used) ? b : a,
          );

          return (
            <Grid columns={columns} gap={4}>
              <MetricCard
                label="Active rewards"
                value={active.length}
                format={(v) => String(Math.round(v))}
                icon={ICONS.activeRewards}
                footer={
                  <Caption text={`${rows.length} in catalogue`} />
                }
              />
              <MetricCard
                label="Redemption rate"
                value={usageRate(claimed, used)}
                format={(v) => formatPct(v, 0)}
                icon={ICONS.lyts}
                deltaPct={usageRate(claimed, used) - 50}
                footer={
                  <Caption
                    text={`${formatCompact(used)} of ${formatCompact(claimed)} claims`}
                  />
                }
              />
              <MetricCard
                label="Most claimed"
                value={mostClaimed.claimed}
                format={formatCompact}
                icon={ICONS.up}
                footer={<Caption text={mostClaimed.name} />}
              />
              <MetricCard
                label="Outstanding liability"
                value={outstanding}
                format={formatLyt}
                icon={ICONS.alert}
                footer={
                  <Caption
                    text={`Least used: ${leastUsed.name} (${formatPct(usageRate(leastUsed.claimed, leastUsed.used), 0)})`}
                  />
                }
              />
            </Grid>
          );
        }}
      </AsyncBoundary>

      <Grid columns={{minWidth: 360, max: 2, repeat: 'fit'}} gap={4}>
        <ChartCard
          title="Redemption"
          subtitle="LYTs redeemed per day"
          resource={redemptions}
        >
          {(d) => (
            <AreaChartView
              data={d}
              xKey="t"
              xFormat={formatDayLabel}
              yFormat={formatCompact}
              series={[{key: 'purchases', label: 'Redeemed'}]}
            />
          )}
        </ChartCard>

        <ChartCard
          title="Issued vs redeemed"
          subtitle="The gap is LYTs still in customers' hands"
          resource={redemptions}
        >
          {(d) => (
            <LineChartView
              data={d}
              xKey="t"
              xFormat={formatDayLabel}
              yFormat={formatCompact}
              series={[
                {key: 'visitors', label: 'Issued'},
                {key: 'purchases', label: 'Redeemed'},
              ]}
            />
          )}
        </ChartCard>
      </Grid>

      <ChartCard
        title="Top rewards"
        subtitle="Claimed vs redeemed, by reward"
        resource={rewards}
      >
        {(rows) => (
          <BarChartView
            data={[...rows].sort((a, b) => b.claimed - a.claimed).slice(0, 6)}
            xKey="name"
            yFormat={formatCompact}
            series={[
              {key: 'claimed', label: 'Claimed'},
              {key: 'used', label: 'Redeemed'},
            ]}
          />
        )}
      </ChartCard>

      <RewardGrid resource={rewards} nowMs={nowMs} />

      <RewardPerformanceTable resource={rewards} />

      <ActivityTimeline resource={activity} limit={6} height={285} />
    </VStack>
  );
}

/**
 * Stands in for the sparkline on metrics with no meaningful time series —
 * "most claimed" is a name, not a trend. MetricCard's `footer` slot exists
 * for exactly this so the card keeps its height and the row stays aligned.
 */
function Caption({text}: {text: string}) {
  return (
    <Text size="xsm" color="secondary">
      {text}
    </Text>
  );
}
