import "server-only";

import { Query } from "node-appwrite";

import { createAdminClient } from "./server";
import { DATABASE_ID, TABLES, type TenantPlan } from "./schema";
import type { TenantContext } from "./tenant-guard";

export type PlanResource = "customers" | "financeEntries" | "software" | "members";

export const PLAN_LIMIT_EXCEEDED = "PLAN_LIMIT_EXCEEDED";

const INF = Number.POSITIVE_INFINITY;

export const PLAN_LIMITS: Record<TenantPlan, Record<PlanResource, number>> = {
  free: {
    customers: 50,
    financeEntries: 100,
    software: 5,
    members: 1,
  },
  pro: {
    customers: INF,
    financeEntries: INF,
    software: INF,
    members: INF,
  },
};

export const RESOURCE_LABELS: Record<PlanResource, string> = {
  customers: "müşteri",
  financeEntries: "finans kaydı",
  software: "yazılım",
  members: "ekip üyesi",
};

export function getEffectivePlan(ctx: TenantContext): TenantPlan {
  const plan = ctx.settings?.plan ?? "free";
  if (plan === "pro") {
    const expires = ctx.settings?.planExpiresAt;
    if (expires && new Date(expires).getTime() < Date.now()) {
      return "free";
    }
  }
  return plan;
}

async function countResource(
  tenantId: string,
  resource: PlanResource,
): Promise<number> {
  const { tablesDB, teams } = createAdminClient();

  if (resource === "members") {
    const result = await teams.listMemberships(tenantId);
    return result.total;
  }

  const tableMap: Record<Exclude<PlanResource, "members">, string> = {
    customers: TABLES.customers,
    financeEntries: TABLES.financeEntries,
    software: TABLES.software,
  };

  const result = await tablesDB.listRows({
    databaseId: DATABASE_ID,
    tableId: tableMap[resource],
    queries: [Query.equal("tenantId", tenantId), Query.limit(1)],
  });
  return result.total;
}

export type PlanUsage = {
  plan: TenantPlan;
  usage: Record<PlanResource, { used: number; limit: number; reached: boolean }>;
};

export async function getPlanUsage(ctx: TenantContext): Promise<PlanUsage> {
  const plan = getEffectivePlan(ctx);
  const limits = PLAN_LIMITS[plan];

  const resources: PlanResource[] = ["customers", "financeEntries", "software", "members"];
  const counts = await Promise.all(resources.map((r) => countResource(ctx.tenantId, r)));

  const usage = {} as PlanUsage["usage"];
  resources.forEach((r, i) => {
    const used = counts[i];
    const limit = limits[r];
    usage[r] = { used, limit, reached: used >= limit };
  });

  return { plan, usage };
}

export class PlanLimitError extends Error {
  code = PLAN_LIMIT_EXCEEDED;
  constructor(public resource: PlanResource, public limit: number) {
    super(`Plan limit reached for ${resource} (${limit})`);
  }
}

export async function requirePlanCapacity(
  ctx: TenantContext,
  resource: PlanResource,
): Promise<void> {
  const plan = getEffectivePlan(ctx);
  const limit = PLAN_LIMITS[plan][resource];
  if (limit === INF) return;

  const used = await countResource(ctx.tenantId, resource);
  if (used >= limit) {
    throw new PlanLimitError(resource, limit);
  }
}

export function isPlanLimitError(e: unknown): e is PlanLimitError {
  return e instanceof PlanLimitError;
}

export function planLimitMessage(resource: PlanResource, limit: number): string {
  const label = RESOURCE_LABELS[resource];
  return `Ücretsiz planda en fazla ${limit} ${label} ekleyebilirsiniz. Pro'ya geçerek sınırı kaldırın.`;
}
