"use server";

import { getAdminUser } from "@/lib/admin-permissions";
import { pool } from "@/lib/db";

export type DateRange = { start: string; end: string };

// ── Types ────────────────────────────────────────────────────────────────────

export type ReportsSummary = {
  gross_sales: number;
  total_orders: number;
  avg_order_value: number;
  pickup_orders: number;
  shipping_orders: number;
  pending_pickups: number;
  completed_pickups: number;
  contacts_added: number;
  campaigns_sent: number;
  messages_logged: number;
};

export type OrderByStop = {
  stop_name: string;
  city: string;
  state: string;
  date: string;
  order_count: number;
  gross_sales: number;
  pending_count: number;
  completed_count: number;
};

export type SalesByProduct = {
  product_name: string;
  units_sold: number;
  gross_revenue: number;
  avg_price: number;
};

export type FulfillmentRow = {
  fulfillment_type: string;
  order_count: number;
  revenue: number;
  pct_of_total: number;
};

export type PickupStatusByStop = {
  stop_name: string;
  city: string;
  date: string;
  total_orders: number;
  pending: number;
  completed: number;
  canceled: number;
};

export type ContactGrowthRow = {
  date: string;
  new_contacts: number;
  imports: number;
  total: number;
};

export type CampaignActivityRow = {
  campaign_name: string;
  status: string;
  campaign_type: string;
  sent_at: string | null;
  messages_logged: number;
};

// ── Helpers ──────────────────────────────────────────────────────────────────
//
// The reports V1 RPCs (`get_reports_summary`, `get_orders_by_stop_report`, etc.)
// from `supabase/migrations/031_reports_v1_rpcs.sql` reference legacy columns
// (`orders.subtotal`, `stops.city/state/date`, `communication_contacts`).
// The SaaS rebuild has a different `orders` schema (`total_cents`, no
// `stop_id`/`city`/`state` columns on `stops`) and a different contacts table
// (`customers` instead of `communication_contacts`). The implementations below
// preserve the same return shape but read from the new tables; some
// fields gracefully degrade to 0 when the underlying data isn't there yet
// (e.g. `stop_name` joins fall back to "—").

/** Substitute the brandId into the SQL — null = platform admin (all brands). */
function brandClause(brandId: string | null, tableAlias = "o"): string {
  return brandId ? `AND ${tableAlias}.brand_id = $3::uuid` : "";
}

function brandParams(brandId: string | null): unknown[] {
  return brandId ? [brandId] : [];
}

// ── Report actions ──────────────────────────────────────────────────────────

export async function getReportsSummary(range: DateRange, brandId: string | null = null) {
  const adminUser = await getAdminUser();
  if (!adminUser) throw new Error("Not authenticated");
  const effectiveBrandId = adminUser.role === "brand_admin" ? adminUser.brand_id : brandId;

  const { rows } = await pool.query<ReportsSummary>(
    `SELECT
       COALESCE(SUM(total_cents), 0)::float / 100.0 AS gross_sales,
       COUNT(*)::int AS total_orders,
       COALESCE(ROUND(AVG(total_cents)::numeric, 2), 0)::float AS avg_order_value,
       0::int AS pickup_orders,
       0::int AS shipping_orders,
       COUNT(*) FILTER (WHERE status = 'pending' AND fulfillment IN ('pickup', 'mixed'))::int AS pending_pickups,
       COUNT(*) FILTER (WHERE status = 'fulfilled' AND fulfillment IN ('pickup', 'mixed'))::int AS completed_pickups,
       0::int AS contacts_added,
       0::int AS campaigns_sent,
       0::int AS messages_logged
     FROM orders o
     WHERE o.placed_at::date BETWEEN $1 AND $2
       AND o.status <> 'canceled'
       ${brandClause(effectiveBrandId)}`,
    [range.start, range.end, ...brandParams(effectiveBrandId)]
  );
  return rows[0] ?? {
    gross_sales: 0,
    total_orders: 0,
    avg_order_value: 0,
    pickup_orders: 0,
    shipping_orders: 0,
    pending_pickups: 0,
    completed_pickups: 0,
    contacts_added: 0,
    campaigns_sent: 0,
    messages_logged: 0,
  };
}

export async function getOrdersByStopReport(range: DateRange, brandId: string | null = null) {
  const adminUser = await getAdminUser();
  if (!adminUser) throw new Error("Not authenticated");
  const effectiveBrandId = adminUser.role === "brand_admin" ? adminUser.brand_id : brandId;

  // The new `stops` table doesn't have city/state/date columns. The reports
  // page is dormant; return an empty list to keep the API surface intact.
  void range;
  void effectiveBrandId;
  return [] as OrderByStop[];
}

export async function getSalesByProductReport(range: DateRange, brandId: string | null = null) {
  const adminUser = await getAdminUser();
  if (!adminUser) throw new Error("Not authenticated");
  const effectiveBrandId = adminUser.role === "brand_admin" ? adminUser.brand_id : brandId;

  const { rows } = await pool.query<{
    product_name: string;
    units_sold: number;
    gross_revenue: number;
    avg_price: number;
  }>(
    `SELECT
       p.name AS product_name,
       COALESCE(SUM(oi.quantity), 0)::int AS units_sold,
       COALESCE(SUM(oi.price_cents * oi.quantity), 0)::float / 100.0 AS gross_revenue,
       COALESCE(ROUND(AVG(oi.price_cents)::numeric, 2), 0)::float / 100.0 AS avg_price
     FROM order_items oi
     JOIN orders o ON o.id = oi.order_id
     JOIN products p ON p.id = oi.product_id
     WHERE o.placed_at::date BETWEEN $1 AND $2
       AND o.status <> 'canceled'
       ${brandClause(effectiveBrandId, "o")}
     GROUP BY p.id, p.name
     ORDER BY gross_revenue DESC`,
    [range.start, range.end, ...brandParams(effectiveBrandId)]
  );
  return rows;
}

export async function getFulfillmentReport(range: DateRange, brandId: string | null = null) {
  const adminUser = await getAdminUser();
  if (!adminUser) throw new Error("Not authenticated");
  const effectiveBrandId = adminUser.role === "brand_admin" ? adminUser.brand_id : brandId;

  const { rows } = await pool.query<{
    fulfillment_type: string;
    order_count: number;
    revenue: number;
    pct_of_total: number;
  }>(
    `WITH base AS (
       SELECT
         fulfillment,
         total_cents::float / 100.0 AS revenue_cents
       FROM orders o
       WHERE o.placed_at::date BETWEEN $1 AND $2
         AND o.status <> 'canceled'
         ${brandClause(effectiveBrandId)}
     )
     SELECT
       fulfillment AS fulfillment_type,
       COUNT(*)::int AS order_count,
       COALESCE(SUM(revenue_cents), 0)::float AS revenue,
       CASE WHEN SUM(SUM(revenue_cents)) OVER () > 0
         THEN ROUND((SUM(revenue_cents) / SUM(SUM(revenue_cents)) OVER () * 100)::numeric, 1)::float
         ELSE 0
       END AS pct_of_total
     FROM base
     GROUP BY fulfillment
     ORDER BY revenue DESC`,
    [range.start, range.end, ...brandParams(effectiveBrandId)]
  );
  return rows;
}

export async function getPickupStatusByStop(range: DateRange, brandId: string | null = null) {
  const adminUser = await getAdminUser();
  if (!adminUser) throw new Error("Not authenticated");
  const effectiveBrandId = adminUser.role === "brand_admin" ? adminUser.brand_id : brandId;

  // The new `stops` table doesn't carry city/date columns. Return an empty
  // list so the page renders gracefully until the stop schema is rehydrated.
  void range;
  void effectiveBrandId;
  return [] as PickupStatusByStop[];
}

export async function getContactGrowthReport(range: DateRange, brandId: string | null = null) {
  const adminUser = await getAdminUser();
  if (!adminUser) throw new Error("Not authenticated");
  const effectiveBrandId = adminUser.role === "brand_admin" ? adminUser.brand_id : brandId;

  // `customers` replaced `communication_contacts`. `source` column is gone,
  // so `imports` is always 0 and `new_contacts` is the day's net add.
  const { rows } = await pool.query<{ date: string; new_contacts: number; imports: number; total: number }>(
    `SELECT
       d::date::text AS date,
       COUNT(c.id) FILTER (WHERE c.created_at::date = d::date)::int AS new_contacts,
       0::int AS imports,
       COUNT(c.id) OVER (ORDER BY d::date)::int AS total
     FROM generate_series($1::date, $2::date, '1 day'::interval) d
     LEFT JOIN customers c
       ON c.created_at::date = d::date
       ${effectiveBrandId ? "AND c.brand_id = $3::uuid" : ""}
     GROUP BY d::date
     ORDER BY d::date DESC`,
    [range.start, range.end, ...brandParams(effectiveBrandId)]
  );
  return rows;
}

export async function getCampaignActivityReport(range: DateRange, brandId: string | null = null) {
  const adminUser = await getAdminUser();
  if (!adminUser) throw new Error("Not authenticated");
  const effectiveBrandId = adminUser.role === "brand_admin" ? adminUser.brand_id : brandId;

  // The legacy `communication_campaigns` table is gone (replaced by
  // `campaigns` + `email_templates`). The reports page is dormant; return
  // an empty list to keep the API surface intact.
  void range;
  void effectiveBrandId;
  return [] as CampaignActivityRow[];
}
