import type { AdminDatasetResult } from "@xtablo/shared-types";
import { Hono } from "hono";
import { getAdminDatasetDefinition, listAdminDatasets } from "../helpers/adminRegistry.js";
import type { BaseEnv } from "../types/app.types.js";

function bucketByDay(values: Array<string | null>) {
  const counts = new Map<string, number>();

  values.forEach((value) => {
    if (!value) {
      return;
    }

    const bucket = value.slice(0, 10);
    counts.set(bucket, (counts.get(bucket) ?? 0) + 1);
  });

  return Array.from(counts.entries())
    .sort(([left], [right]) => left.localeCompare(right))
    .map(([label, value]) => ({ label, value }));
}

function bucketByValue(values: Array<string | null>, emptyLabel: string) {
  const counts = new Map<string, number>();

  values.forEach((value) => {
    const bucket = value?.trim() || emptyLabel;
    counts.set(bucket, (counts.get(bucket) ?? 0) + 1);
  });

  return Array.from(counts.entries())
    .sort(([left], [right]) => left.localeCompare(right))
    .map(([label, value]) => ({ label, value }));
}

function bucketTabloAccess(rows: Array<{ is_active: boolean | null; is_admin: boolean | null }>) {
  const counts = new Map<string, number>([
    ["Active Member", 0],
    ["Active Admin", 0],
    ["Inactive", 0],
  ]);

  rows.forEach((row) => {
    if (row.is_active) {
      const label = row.is_admin ? "Active Admin" : "Active Member";
      counts.set(label, (counts.get(label) ?? 0) + 1);
      return;
    }

    counts.set("Inactive", (counts.get("Inactive") ?? 0) + 1);
  });

  return Array.from(counts.entries()).map(([label, value]) => ({ label, value }));
}

type AdminDatasetPayload = Pick<
  AdminDatasetResult,
  "chartType" | "dimensionLabel" | "metricLabel" | "points"
>;

async function getDatasetPoints(
  datasetId: string,
  supabase: BaseEnv["Variables"]["supabase"]
): Promise<AdminDatasetPayload> {
  switch (datasetId) {
    case "profile_growth": {
      const { data, error } = await supabase
        .from("profiles")
        .select("created_at")
        .order("created_at", { ascending: true })
        .limit(365);

      if (error) {
        throw new Error(error.message);
      }

      return {
        chartType: "line",
        dimensionLabel: "Created Day",
        metricLabel: "Users Created",
        points: bucketByDay((data ?? []).map((row) => row.created_at)),
      };
    }
    case "plan_mix": {
      const { data, error } = await supabase.from("profiles").select("plan").limit(500);

      if (error) {
        throw new Error(error.message);
      }

      return {
        chartType: "donut",
        dimensionLabel: "Plan",
        metricLabel: "Users",
        points: bucketByValue(
          (data ?? []).map((row) => row.plan),
          "No Plan"
        ),
      };
    }
    case "tablo_access_mix": {
      const { data, error } = await supabase
        .from("tablo_access")
        .select("is_active,is_admin")
        .limit(500);

      if (error) {
        throw new Error(error.message);
      }

      return {
        chartType: "bar",
        dimensionLabel: "Access Type",
        metricLabel: "Rows",
        points: bucketTabloAccess(data ?? []),
      };
    }
    default:
      throw new Error(`Unknown admin dataset '${datasetId}'`);
  }
}

export const getAdminDatasetsRouter = () => {
  const adminDatasetsRouter = new Hono<BaseEnv>();

  adminDatasetsRouter.get("/", async (c) => {
    return c.json({ datasets: listAdminDatasets() }, 200);
  });

  adminDatasetsRouter.get("/:datasetId", async (c) => {
    const supabase = c.get("supabase");
    const datasetId = c.req.param("datasetId");
    const definition = getAdminDatasetDefinition(datasetId);

    if (!definition) {
      return c.json({ error: `Admin dataset '${datasetId}' is not registered` }, 404);
    }

    try {
      const dataset = await getDatasetPoints(datasetId, supabase);

      return c.json(
        {
          ...definition,
          ...dataset,
        } satisfies AdminDatasetResult,
        200
      );
    } catch {
      return c.json({ error: `Failed to load admin dataset '${datasetId}'` }, 500);
    }
  });

  return adminDatasetsRouter;
};
