import type { LoaderFunctionArgs } from "react-router";
import { useLoaderData, useNavigate } from "react-router";
import {
  Page,
  Card,
  Text,
  BlockStack,
  InlineGrid,
  DataTable,
  Badge,
  Banner,
  EmptyState,
} from "@shopify/polaris";
import { authenticate } from "../shopify.server";
import prisma from "../db.server";

// ── Timezone helpers ──────────────────────────────────────────────────────────

function toDateKeyInTz(date: Date, tz: string) {
  return new Intl.DateTimeFormat("en-CA", {
    timeZone: tz,
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
  }).format(date); // "YYYY-MM-DD"
}

function getMinutesInTz(date: Date, tz: string) {
  const parts = new Intl.DateTimeFormat("en-US", {
    timeZone: tz,
    hour: "2-digit",
    minute: "2-digit",
    hourCycle: "h23",
  }).formatToParts(date);
  const h = Number(parts.find((p) => p.type === "hour")?.value ?? 0);
  const m = Number(parts.find((p) => p.type === "minute")?.value ?? 0);
  return h * 60 + m;
}

function getDayOfWeekInTz(date: Date, tz: string) {
  const wd = new Intl.DateTimeFormat("en-US", {
    timeZone: tz,
    weekday: "short",
  }).format(date);
  return ({ Sun: 0, Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6 } as Record<string, number>)[wd] ?? 0;
}

function toMoney(input: any): number {
  const raw = input?.shopMoney?.amount ?? input?.presentmentMoney?.amount ?? input?.amount;
  const n = Number(raw);
  return Number.isFinite(n) ? n : 0;
}

// ── Loader ────────────────────────────────────────────────────────────────────

export const loader = async ({ request }: LoaderFunctionArgs) => {
  const { session, admin } = await authenticate.admin(request);
  const shop = session.shop;

  const settings = await prisma.appSettings.findUnique({ where: { shop } });
  const timezone = settings?.timezone ?? "UTC";

  // Week start (Sunday 00:00 in the shop's timezone, not server UTC)
  const now = new Date();
  const todayKeyForWeek = toDateKeyInTz(now, timezone); // "YYYY-MM-DD"
  const todayDateInTz = new Date(todayKeyForWeek + "T00:00:00.000Z");
  // Find how many days since Sunday in shop timezone
  const dowForWeek = new Intl.DateTimeFormat("en-US", { timeZone: timezone, weekday: "short" }).format(now);
  const dowIndex = ({ Sun: 0, Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6 } as Record<string, number>)[dowForWeek] ?? 0;
  const weekStart = new Date(todayDateInTz);
  weekStart.setUTCDate(weekStart.getUTCDate() - dowIndex);

  // Today's upcoming deal slots — use Intl.DateTimeFormat (spec-compliant, never Invalid Date)
  const nowParts = new Intl.DateTimeFormat("en-US", {
    timeZone: timezone,
    weekday: "short",
    hour: "2-digit",
    minute: "2-digit",
    hourCycle: "h23",
  }).formatToParts(new Date());
  const getPart = (type: string) => nowParts.find((p) => p.type === type)?.value ?? "0";
  const todayDow = ({ Sun: 0, Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6 } as Record<string, number>)[getPart("weekday")] ?? 0;
  const nowHour = parseInt(getPart("hour"), 10);
  const nowMinute = parseInt(getPart("minute"), 10);
  const nowMinutes = nowHour * 60 + nowMinute;
  const todayKey = toDateKeyInTz(new Date(), timezone); // "YYYY-MM-DD"

  // Fetch ALL of today's deals (past + live + upcoming) so we can show real statuses
  const rawToday = await prisma.dealSlot.findMany({
    where: {
      shop,
      isActive: true,
      OR: [
        { specificDate: todayKey },
        { specificDate: null, dayOfWeek: todayDow },
      ],
    },
    orderBy: { startHour: "asc" },
    take: 20,
  });

  // Annotate each deal with its real status
  const upcomingToday = rawToday.map((deal) => {
    const start = deal.startHour * 60 + deal.startMinute;
    const end = start + deal.durationMinutes;
    const status =
      nowMinutes < start ? "upcoming" :
        nowMinutes < end ? "live" : "past";
    return { ...deal, status };
  });

  // All active deal slots (for matching orders)
  const dealSlots = await prisma.dealSlot.findMany({
    where: { shop, isActive: true },
  });

  // ── Fetch shop currency ───────────────────────────────────────────────────
  let currencyCode = "USD";
  try {
    const shopResp = await admin.graphql(`#graphql query { shop { currencyCode } }`);
    const shopJson = await shopResp.json() as any;
    currencyCode = shopJson?.data?.shop?.currencyCode ?? "USD";
  } catch { /* fall back to USD */ }

  // ── Fetch this week's orders from Admin API ──────────────────────────────
  // Aggregate in-memory — never write increments on every load (that double-counts).
  type SlotStats = { unitsSold: number; revenue: number; title: string };
  const slotStats = new Map<string, SlotStats>();
  let weekUnits = 0;
  let weekRevenue = 0;

  try {
    const resp = await admin.graphql(
      `#graphql
      query WeekOrders($q: String!) {
        orders(first: 250, query: $q, sortKey: CREATED_AT, reverse: true) {
          nodes {
            id
            createdAt
            lineItems(first: 50) {
              nodes {
                quantity
                discountedUnitPriceSet { shopMoney { amount } }
                originalUnitPriceSet  { shopMoney { amount } }
                product { id title }
              }
            }
          }
        }
      }`,
      { variables: { q: `created_at:>=${weekStart.toISOString()}` } }
    );

    const json = await resp.json() as any;
    const orders: any[] = json?.data?.orders?.nodes ?? [];

    for (const order of orders) {
      const createdAt = new Date(order.createdAt);
      const dow = getDayOfWeekInTz(createdAt, timezone);
      const minutes = getMinutesInTz(createdAt, timezone);

      for (const li of order.lineItems?.nodes ?? []) {
        const productGid: string | undefined = li?.product?.id;
        if (!productGid) continue;

        const slot = dealSlots.find((s) => {
          if (s.productId !== productGid || s.dayOfWeek !== dow) return false;
          const start = s.startHour * 60 + s.startMinute;
          return minutes >= start && minutes < start + s.durationMinutes;
        });
        if (!slot) continue;

        const qty = Math.max(0, Number(li.quantity ?? 0));
        if (!qty) continue;

        const unit = toMoney(li.discountedUnitPriceSet) || toMoney(li.originalUnitPriceSet);
        const rev = unit * qty;

        weekUnits += qty;
        weekRevenue += rev;

        const prev = slotStats.get(slot.id) ?? { unitsSold: 0, revenue: 0, title: slot.productTitle };
        slotStats.set(slot.id, {
          unitsSold: prev.unitsSold + qty,
          revenue: prev.revenue + rev,
          title: slot.productTitle,
        });
      }
    }
  } catch (e) {
    console.error("Failed to fetch orders for analytics:", e);
  }

  // Top deals sorted by revenue
  const topDeals = [...slotStats.values()]
    .sort((a, b) => b.revenue - a.revenue)
    .slice(0, 5);

  return {
    hasSettings: !!settings,
    upcomingToday,
    weekSummary: { unitsSold: weekUnits, revenue: weekRevenue },
    topDeals,
    currencyCode,
  };
};

// ── UI ────────────────────────────────────────────────────────────────────────

const STATUS_COLORS: Record<string, { bg: string; color: string; label: string }> = {
  current: { bg: "#d4edda", color: "#155724", label: "Live now" },
  upcoming: { bg: "#cce5ff", color: "#004085", label: "Upcoming" },
  past: { bg: "#f6f6f7", color: "#6d7175", label: "Past" },
};

export default function Dashboard() {
  const { hasSettings, upcomingToday, weekSummary, topDeals, currencyCode } =
    useLoaderData<typeof loader>();
  const navigate = useNavigate();

  const fmt = (n: number) =>
    new Intl.NumberFormat("en-US", { style: "currency", currency: currencyCode }).format(n);

  return (
    <Page
      title="Deal of the Hour"
      primaryAction={{ content: "Manage Schedule", onAction: () => navigate("/app/schedule") }}
      secondaryActions={[
        { content: "Past Deals", onAction: () => navigate("/app/analytics") },
        { content: "Widget Placement", onAction: () => navigate("/app/placement") },
        { content: "Settings", onAction: () => navigate("/app/settings") },
      ]}
    >
      <BlockStack gap="500">
        {!hasSettings && (
          <Banner
            title="Welcome! Set up your timezone first"
            action={{ content: "Go to Settings", onAction: () => navigate("/app/settings") }}
            tone="warning"
          >
            <p>Configure your timezone and deal interval before creating your first deal.</p>
          </Banner>
        )}

        {/* KPI Cards */}
        <InlineGrid columns={3} gap="400">
          <Card>
            <BlockStack gap="200">
              <Text as="p" variant="bodyMd" tone="subdued">This Week — Units Sold</Text>
              <Text as="p" variant="headingXl">{weekSummary.unitsSold}</Text>
            </BlockStack>
          </Card>
          <Card>
            <BlockStack gap="200">
              <Text as="p" variant="bodyMd" tone="subdued">This Week — Revenue</Text>
              <Text as="p" variant="headingXl">{fmt(weekSummary.revenue)}</Text>
            </BlockStack>
          </Card>
          <Card>
            <BlockStack gap="200">
              <Text as="p" variant="bodyMd" tone="subdued">Deals Today</Text>
              <Text as="p" variant="headingXl">{upcomingToday.filter((d) => d.status !== "past").length} <span style={{ fontSize: 16, fontWeight: 400, color: "#6d7175" }}>/ {upcomingToday.length}</span></Text>
            </BlockStack>
          </Card>
        </InlineGrid>

        {/* Today's upcoming deals — custom table, no DataTable overflow issues */}
        <Card padding="0">
          <div style={{ padding: "16px 20px 12px", borderBottom: "1px solid #e1e3e5", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
            <Text as="h2" variant="headingMd">Today's Deals</Text>
            <span
              onClick={() => navigate("/app/schedule")}
              style={{ fontSize: 13, color: "#008060", cursor: "pointer", textDecoration: "underline" }}
            >
              View full schedule →
            </span>
          </div>

          {(() => {
            const activeDeals = upcomingToday.filter((d) => d.status !== "past");
            if (activeDeals.length === 0) {
              return (
                <div style={{ padding: "48px 24px", textAlign: "center" }}>
                  <Text as="p" tone="subdued" variant="bodyLg">
                    {upcomingToday.length > 0
                      ? "All deals for today have ended."
                      : "No deals scheduled for today."}
                  </Text>
                  <div style={{ marginTop: 12, display: "flex", gap: 16, justifyContent: "center", flexWrap: "wrap" }}>
                    <span
                      onClick={() => navigate("/app/schedule")}
                      style={{ fontSize: 14, color: "#008060", cursor: "pointer", textDecoration: "underline" }}
                    >
                      Add deals to the schedule →
                    </span>
                    {upcomingToday.length > 0 && (
                      <span
                        onClick={() => navigate("/app/analytics")}
                        style={{ fontSize: 14, color: "#008060", cursor: "pointer", textDecoration: "underline" }}
                      >
                        View past deals →
                      </span>
                    )}
                  </div>
                </div>
              );
            }
            return (
              <table style={{ width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }}>
                <thead>
                  <tr style={{ background: "#f9fafb" }}>
                    {["Time", "Product", "SKU", "Discount", "Status"].map((h) => (
                      <th key={h} style={{
                        padding: "10px 16px",
                        textAlign: "left",
                        fontSize: 12,
                        fontWeight: 600,
                        color: "#6d7175",
                        borderBottom: "1px solid #e1e3e5",
                        width: h === "Product" ? "40%" : h === "Time" ? "10%" : h === "Status" ? "12%" : "auto",
                      }}>{h}</th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {activeDeals.map((deal, i) => {
                    const s = STATUS_COLORS[deal.status === "live" ? "current" : deal.status] ?? STATUS_COLORS["upcoming"];
                    return (
                      <tr key={deal.id} style={{ borderBottom: i < activeDeals.length - 1 ? "1px solid #f1f1f1" : "none" }}>
                        <td style={{ padding: "12px 16px", fontSize: 13, fontWeight: 600, whiteSpace: "nowrap" }}>
                          {String(deal.startHour).padStart(2, "0")}:{String(deal.startMinute).padStart(2, "0")}
                        </td>
                        <td style={{ padding: "12px 16px", fontSize: 13, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                          {deal.productTitle}
                        </td>
                        <td style={{ padding: "12px 16px", fontSize: 12, color: "#6d7175" }}>
                          {deal.productSku || "—"}
                        </td>
                        <td style={{ padding: "12px 16px", fontSize: 13 }}>
                          {deal.discountType === "percentage"
                            ? `${deal.discountValue}% off`
                            : `${fmt(deal.discountValue)} off`}
                        </td>
                        <td style={{ padding: "12px 16px" }}>
                          <span style={{
                            display: "inline-block",
                            padding: "3px 10px",
                            borderRadius: 20,
                            fontSize: 12,
                            fontWeight: 600,
                            background: s.bg,
                            color: s.color,
                            whiteSpace: "nowrap",
                          }}>
                            {s.label}
                          </span>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            );
          })()}
        </Card>

        {/* Top deals this week */}
        {topDeals.length > 0 && (
          <Card padding="0">
            <div style={{ padding: "16px 20px 12px", borderBottom: "1px solid #e1e3e5", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
              <Text as="h2" variant="headingMd">Top Deals This Week</Text>
              <span
                onClick={() => navigate("/app/analytics")}
                style={{ fontSize: 13, color: "#008060", cursor: "pointer", textDecoration: "underline" }}
              >
                View all past deals →
              </span>
            </div>
            <table style={{ width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }}>
              <thead>
                <tr style={{ background: "#f9fafb" }}>
                  {["Product", "Units Sold", "Revenue"].map((h) => (
                    <th key={h} style={{
                      padding: "10px 16px",
                      textAlign: h === "Product" ? "left" : "right",
                      fontSize: 12,
                      fontWeight: 600,
                      color: "#6d7175",
                      borderBottom: "1px solid #e1e3e5",
                    }}>{h}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {topDeals.map((d, i) => (
                  <tr key={i} style={{ borderBottom: i < topDeals.length - 1 ? "1px solid #f1f1f1" : "none" }}>
                    <td style={{ padding: "12px 16px", fontSize: 13, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{d.title}</td>
                    <td style={{ padding: "12px 16px", fontSize: 13, textAlign: "right", fontWeight: 600 }}>{d.unitsSold}</td>
                    <td style={{ padding: "12px 16px", fontSize: 13, textAlign: "right", fontWeight: 600, color: "#008060" }}>{fmt(d.revenue)}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </Card>
        )}

        {/* Widget placement CTA */}
        <Card>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16, flexWrap: "wrap" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
              <span style={{ fontSize: 28 }}>📍</span>
              <BlockStack gap="100">
                <Text as="p" variant="headingMd">Show the Widget on your Storefront</Text>
                <Text as="p" variant="bodySm" tone="subdued">
                  Follow our step-by-step guide to place the deal widget on your homepage, product pages, cart, and more — no code needed.
                </Text>
              </BlockStack>
            </div>
            <div style={{ flexShrink: 0 }}>
              <button
                onClick={() => navigate("/app/placement")}
                style={{
                  padding: "8px 18px",
                  borderRadius: 6,
                  border: "none",
                  background: "#008060",
                  color: "#fff",
                  fontWeight: 600,
                  fontSize: 13,
                  cursor: "pointer",
                  whiteSpace: "nowrap",
                }}
              >
                Set up widget placement →
              </button>
            </div>
          </div>
        </Card>

      </BlockStack>
    </Page>
  );
}
