import { AppError } from "../lib/errors.js";
import { isoNow } from "../lib/utils.js";
import { supabaseAdmin } from "../lib/supabase.js";

export type OrganizationQuota = {
  planCode: string;
  contactLimit: number | null;
  monthlyEmailLimit: number | null;
  contactCount: number;
  monthlyEmailCount: number;
};

const betaModeLimits = {
  code: "beta",
  contactLimit: 100000,
  monthlyEmailLimit: null,
} as const;

async function getBetaModePlan() {
  const { data, error } = await supabaseAdmin
    .from("admin_settings")
    .select("value")
    .eq("key", "beta_mode")
    .maybeSingle();

  if (error) {
    throw new AppError(500, "ADMIN_SETTING_LOOKUP_FAILED", error.message);
  }

  const enabled =
    data &&
    typeof data.value === "object" &&
    data.value !== null &&
    "enabled" in data.value &&
    Boolean((data.value as Record<string, unknown>).enabled);

  return enabled ? betaModeLimits : null;
}

async function getCurrentPlan(organizationId: string) {
  const betaModePlan = await getBetaModePlan();

  if (betaModePlan) {
    return betaModePlan;
  }

  const { data, error } = await supabaseAdmin
    .from("organization_subscriptions")
    .select("status, plan_definitions(code, contact_limit, monthly_email_limit)")
    .eq("organization_id", organizationId)
    .eq("status", "active")
    .order("created_at", { ascending: false })
    .limit(1)
    .single();

  if (error || !data) {
    throw new AppError(500, "PLAN_LOOKUP_FAILED", error?.message ?? "No active plan is configured for this organization.");
  }

  const plan = Array.isArray(data.plan_definitions) ? data.plan_definitions[0] : data.plan_definitions;

  if (!plan) {
    throw new AppError(500, "PLAN_LOOKUP_FAILED", "The active subscription has no plan definition.");
  }

  return {
    code: plan.code as string,
    contactLimit: plan.contact_limit as number | null,
    monthlyEmailLimit: plan.monthly_email_limit as number | null
  };
}

async function getUsageRow(organizationId: string) {
  const periodStart = new Date();
  periodStart.setUTCDate(1);
  periodStart.setUTCHours(0, 0, 0, 0);
  const periodKey = periodStart.toISOString().slice(0, 10);

  const { data: existing } = await supabaseAdmin
    .from("monthly_usage_counters")
    .select("id, contacts_count, emails_sent_count")
    .eq("organization_id", organizationId)
    .eq("period_start", periodKey)
    .maybeSingle();

  if (existing) {
    return { ...existing, periodKey };
  }

  const { data, error } = await supabaseAdmin
    .from("monthly_usage_counters")
    .insert({
      organization_id: organizationId,
      period_start: periodKey,
      contacts_count: 0,
      emails_sent_count: 0,
      updated_at: isoNow()
    })
    .select("id, contacts_count, emails_sent_count")
    .single();

  if (error || !data) {
    throw new AppError(500, "USAGE_COUNTER_FAILED", error?.message ?? "Unable to initialize monthly usage.");
  }

  return { ...data, periodKey };
}

export async function getOrganizationQuota(organizationId: string): Promise<OrganizationQuota> {
  const plan = await getCurrentPlan(organizationId);
  const usage = await getUsageRow(organizationId);
  const { count } = await supabaseAdmin
    .from("contacts")
    .select("id", { count: "exact", head: true })
    .eq("organization_id", organizationId);

  return {
    planCode: plan.code,
    contactLimit: plan.contactLimit,
    monthlyEmailLimit: plan.monthlyEmailLimit,
    contactCount: count ?? 0,
    monthlyEmailCount: usage.emails_sent_count as number
  };
}

export async function enforceContactQuota(organizationId: string, incomingContacts: number) {
  const quota = await getOrganizationQuota(organizationId);

  if (quota.contactLimit !== null && quota.contactCount + incomingContacts > quota.contactLimit) {
    throw new AppError(
      400,
      "CONTACT_LIMIT_EXCEEDED",
      `This import would exceed the plan limit of ${quota.contactLimit} contacts.`
    );
  }
}

export async function enforceEmailQuota(organizationId: string, outgoingCount: number) {
  const quota = await getOrganizationQuota(organizationId);

  if (quota.monthlyEmailLimit !== null && quota.monthlyEmailCount + outgoingCount > quota.monthlyEmailLimit) {
    throw new AppError(
      400,
      "EMAIL_LIMIT_EXCEEDED",
      `This send would exceed the monthly email limit of ${quota.monthlyEmailLimit}.`
    );
  }
}

export async function incrementEmailUsage(organizationId: string, sentCount: number) {
  const usage = await getUsageRow(organizationId);

  const { error } = await supabaseAdmin
    .from("monthly_usage_counters")
    .update({
      emails_sent_count: (usage.emails_sent_count as number) + sentCount,
      updated_at: isoNow()
    })
    .eq("id", usage.id);

  if (error) {
    throw new AppError(500, "USAGE_UPDATE_FAILED", error.message);
  }
}

export async function syncContactUsage(organizationId: string) {
  const usage = await getUsageRow(organizationId);
  const { count } = await supabaseAdmin
    .from("contacts")
    .select("id", { count: "exact", head: true })
    .eq("organization_id", organizationId);

  await supabaseAdmin
    .from("monthly_usage_counters")
    .update({
      contacts_count: count ?? 0,
      updated_at: isoNow()
    })
    .eq("id", usage.id);
}
