import { getAdminUser } from "@/lib/admin-permissions";
import { getActiveBrandId } from "@/lib/brand-scope";
import { pool } from "@/lib/db";
import PageHeader from "@/components/admin/PageHeader";
import { CardList, CardListItem } from "@/components/admin/CardList";
import StatusPill, { type StatusKind } from "@/components/admin/StatusPill";
import EmptyState from "@/components/admin/EmptyState";
import PullToRefresh from "@/components/admin/PullToRefresh";
import StopsDatePicker from "@/components/admin/stops/StopsDatePicker";

export const dynamic = "force-dynamic";

/**
 * Row shape returned from the stops query. The legacy `stops` table uses
 * separate `date` (DATE) and `time` (TEXT) columns, not a combined
 * `scheduled_at` ISO string — the plan's example was speculative about
 * the schema, so we mirror the v1 stops page shape and adapt.
 */
interface DbStopRow {
  id: string;
  city: string | null;
  state: string | null;
  date: string;
  time: string | null;
  location: string;
  status: string;
  brand_id: string;
  address: string | null;
  zip: string | null;
  cutoff_date: string | null;
  customer_count: number;
}

/**
 * Map the legacy `stops.status` ('active' | 'paused' | 'closed') onto the
 * StatusPill's `StatusKind` vocabulary. Mirrors the v1 page's
 * `s.status === "active"` check but extends it to cover the full enum.
 *
 * - 'active'  → 'scheduled'  (default — accepting orders)
 * - 'paused'  → 'in-transit' (temporarily closed, like a truck en route)
 * - 'closed'  → 'completed'  (final state)
 */
function stopStatusKind(s: string): StatusKind {
  if (s === "paused") return "in-transit";
  if (s === "closed") return "completed";
  return "scheduled";
}

/**
 * Parse the hour (0-23) from a free-form time string. The `stops.time`
 * column is TEXT and accepts both 24h ("14:30") and 12h ("9:00 AM",
 * "9 AM", "2:30pm") formats. Returns null for unparseable input so
 * those stops fall into the "Anytime" bucket.
 */
function parseHour(time: string | null): number | null {
  if (!time) return null;
  const t = time.trim();
  // 12h format with optional minutes: "9:00 AM" / "9 AM" / "9:00am" / "2:30 PM"
  const m12 = t.match(/^(\d{1,2})(?::\d{2})?\s*(am|pm)$/i);
  if (m12) {
    let h = parseInt(m12[1], 10);
    const isPm = m12[2].toLowerCase() === "pm";
    if (h < 1 || h > 12) return null;
    if (h === 12) h = isPm ? 12 : 0;
    else if (isPm) h += 12;
    return h;
  }
  // 24h format: "14:30" or "14"
  const m24 = t.match(/^(\d{1,2})(?::\d{2})?$/);
  if (m24) {
    const h = parseInt(m24[1], 10);
    return h >= 0 && h < 24 ? h : null;
  }
  return null;
}

type TimeBucket = "Morning" | "Afternoon" | "Evening" | "Anytime";

function bucketFor(time: string | null): TimeBucket {
  const h = parseHour(time);
  if (h === null) return "Anytime";
  if (h < 12) return "Morning";
  if (h < 17) return "Afternoon";
  return "Evening";
}

const BUCKET_ORDER: TimeBucket[] = ["Morning", "Afternoon", "Evening", "Anytime"];

/** Bucket a list of stops into the four time-of-day groups. */
function groupStopsByBucket(stops: DbStopRow[]): Record<TimeBucket, DbStopRow[]> {
  const grouped: Record<TimeBucket, DbStopRow[]> = {
    Morning: [],
    Afternoon: [],
    Evening: [],
    Anytime: [],
  };
  for (const s of stops) {
    grouped[bucketFor(s.time)].push(s);
  }
  return grouped;
}

/** Build a Google Maps directions URL for a stop's address. */
function mapsUrlFor(stop: DbStopRow): string | null {
  const parts = [stop.address, stop.city, stop.state, stop.zip].filter(Boolean);
  if (parts.length === 0) return null;
  return `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(
    parts.join(", "),
  )}`;
}

function formatDateHeading(d: Date): string {
  return d.toLocaleDateString("en-US", {
    weekday: "long",
    month: "short",
    day: "numeric",
  });
}

function formatTimeLabel(time: string | null): string {
  if (!time) return "—";
  const t = time.trim();
  // If it's already a "9:00 AM" or "9:00AM" style, return as-is
  if (/[ap]m$/i.test(t)) return t.toUpperCase();
  // 24h "14:30" → "2:30 PM"
  const m = t.match(/^(\d{1,2}):(\d{2})$/);
  if (m) {
    let h = parseInt(m[1], 10);
    const min = m[2];
    const ampm = h >= 12 ? "PM" : "AM";
    if (h === 0) h = 12;
    else if (h > 12) h -= 12;
    return `${h}:${min} ${ampm}`;
  }
  return t;
}

export default async function StopsV2Page({
  searchParams,
}: {
  searchParams: Promise<{ date?: string }>;
}) {
  const adminUser = await getAdminUser();
  if (!adminUser) return null;

  const [activeBrandId, params] = await Promise.all([
    getActiveBrandId(adminUser),
    searchParams,
  ]);

  // Resolve the target date. `searchParams.date` is a YYYY-MM-DD string.
  // Fall back to "today" in the user's local timezone (not UTC, so the
  // displayed heading matches what they expect).
  let dateObj: Date;
  if (params.date) {
    const parsed = new Date(params.date);
    if (!isNaN(parsed.getTime())) {
      dateObj = parsed;
    } else {
      const now = new Date();
      dateObj = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    }
  } else {
    const now = new Date();
    dateObj = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  }
  const dateStr = `${dateObj.getFullYear()}-${String(dateObj.getMonth() + 1).padStart(2, "0")}-${String(dateObj.getDate()).padStart(2, "0")}`;

  // Build the brand filter. Mirrors the v1 stops page's brand-scoping
  // pattern: explicit active brand > platform_admin "all brands" >
  // multi-brand membership list.
  let stops: DbStopRow[] = [];
  let error: string | null = null;
  try {
    const selectFields = `
      s.id, s.city, s.state, s.date::text AS date, s."time", s.location,
      s.status, s.brand_id, s.address, s.zip, s.cutoff_date,
      (SELECT COUNT(*)::int FROM orders o WHERE o.stop_id = s.id) AS customer_count
    `;
    const orderBy = `s."time" ASC NULLS LAST, s.location ASC`;
    const baseWhere = `s.date = $1`;

    if (activeBrandId) {
      const result = await pool.query<DbStopRow>(
        `SELECT ${selectFields}
           FROM stops s
          WHERE ${baseWhere} AND s.brand_id = $2
          ORDER BY ${orderBy}
          LIMIT 200`,
        [dateStr, activeBrandId],
      );
      stops = result.rows;
    } else if (adminUser.role === "platform_admin") {
      const result = await pool.query<DbStopRow>(
        `SELECT ${selectFields}
           FROM stops s
          WHERE ${baseWhere}
          ORDER BY ${orderBy}
          LIMIT 200`,
        [dateStr],
      );
      stops = result.rows;
    } else {
      const brandIds = adminUser.brand_ids ?? [];
      if (brandIds.length === 0) {
        // No accessible brands → empty list, no need to query.
        stops = [];
      } else {
        const result = await pool.query<DbStopRow>(
          `SELECT ${selectFields}
             FROM stops s
            WHERE ${baseWhere} AND s.brand_id = ANY($2::uuid[])
            ORDER BY ${orderBy}
            LIMIT 200`,
          [dateStr, brandIds],
        );
        stops = result.rows;
      }
    }
  } catch (e) {
    error = e instanceof Error ? e.message : String(e);
    console.error("[admin/v2/stops] query error:", error);
  }

  const headerDate = dateObj;

  if (error) {
    return (
      <main>
        <PageHeader title="Stops" actions={<StopsDatePicker value={headerDate} />} />
        <div className="px-4 pb-24">
          <EmptyState
            title="Couldn't load stops"
            description={error}
            icon={<span aria-hidden="true">⚠️</span>}
          />
        </div>
      </main>
    );
  }

  if (stops.length === 0) {
    return (
      <main>
        <PageHeader
          title="Stops"
          subtitle={formatDateHeading(headerDate)}
          actions={<StopsDatePicker value={headerDate} />}
        />
        <PullToRefresh>
          <EmptyState
            title="No stops scheduled"
            description="Add a stop to start routing."
            icon={<span aria-hidden="true">🚚</span>}
          />
        </PullToRefresh>
      </main>
    );
  }

  // Group by time-of-day bucket. Use Map to preserve insertion order.
  const grouped = groupStopsByBucket(stops);

  return (
    <main>
      <PageHeader
        title="Stops"
        subtitle={formatDateHeading(headerDate)}
        actions={<StopsDatePicker value={headerDate} />}
      />
      <PullToRefresh>
        {BUCKET_ORDER.reduce<typeof BUCKET_ORDER>((acc, bucket) => {
          if (grouped[bucket].length > 0) acc.push(bucket);
          return acc;
        }, []).map((bucket) => (
          <section key={bucket}>
            <h2
              className="sticky top-0 px-4 py-2 text-label font-semibold"
              style={{
                backgroundColor: "var(--color-surface)",
                color: "var(--color-text-muted)",
                letterSpacing: "0.02em",
              }}
            >
              {bucket.toUpperCase()}
            </h2>
            <CardList ariaLabel={`${bucket} stops`}>
              {grouped[bucket].map((stop) => {
                const href = mapsUrlFor(stop);
                return (
                  <CardListItem key={stop.id} href={href ?? "#"}>
                    <div className="flex items-center gap-3">
                      <div
                        className="text-h1 font-display shrink-0"
                        style={{ fontWeight: 600, minWidth: "72px" }}
                      >
                        {formatTimeLabel(stop.time)}
                      </div>
                      <div className="flex-1 min-w-0">
                        <div
                          className="text-h2"
                          style={{ fontWeight: 700, lineHeight: 1.3 }}
                        >
                          {stop.address ??
                            stop.location ??
                            ([stop.city, stop.state].filter(Boolean).join(", ") ||
                              "Stop")}
                        </div>
                        <div
                          className="text-meta mt-1"
                          style={{ color: "var(--color-text-muted)" }}
                        >
                          {stop.customer_count} customer
                          {stop.customer_count === 1 ? "" : "s"}
                          {stop.cutoff_date != null
                            ? ` · Cutoff ${stop.cutoff_date}`
                            : ""}
                        </div>
                      </div>
                      <StatusPill status={stopStatusKind(stop.status)} />
                    </div>
                  </CardListItem>
                );
              })}
            </CardList>
          </section>
        ))}
      </PullToRefresh>
    </main>
  );
}
