import type { PrismaClient } from '@prisma/client';
import {
  DEFAULT_PREMIUM_TIER_CONFIGS,
  featureKeyForResource,
  isAssignmentActive,
  limitKeyForResource,
  parsePremiumFeatures,
  PremiumTierSchema,
  type PremiumLimitResource,
  type PremiumTier,
  type PremiumTierConfig
} from '@nexumi/shared';

export class PremiumLimitError extends Error {
  constructor(
    public readonly code: 'feature_disabled' | 'limit_reached',
    public readonly resource: PremiumLimitResource,
    public readonly limit: number,
    public readonly current: number,
    public readonly tier: PremiumTier
  ) {
    super(code);
  }
}

function toConfig(row: {
  tier: string;
  maxTags: number;
  maxFeeds: number;
  maxBackups: number;
  features: unknown;
}): PremiumTierConfig {
  return {
    tier: PremiumTierSchema.parse(row.tier),
    maxTags: row.maxTags,
    maxFeeds: row.maxFeeds,
    maxBackups: row.maxBackups,
    features: parsePremiumFeatures(row.features)
  };
}

export async function ensurePremiumTierConfigs(prisma: PrismaClient): Promise<PremiumTierConfig[]> {
  const configs: PremiumTierConfig[] = [];
  for (const tier of PremiumTierSchema.options) {
    const defaults = DEFAULT_PREMIUM_TIER_CONFIGS[tier];
    const row = await prisma.premiumTierConfig.upsert({
      where: { tier },
      create: {
        tier,
        maxTags: defaults.maxTags,
        maxFeeds: defaults.maxFeeds,
        maxBackups: defaults.maxBackups,
        features: defaults.features
      },
      update: {}
    });
    configs.push(toConfig(row));
  }
  return configs;
}

export async function getPremiumTierConfigs(prisma: PrismaClient): Promise<PremiumTierConfig[]> {
  return ensurePremiumTierConfigs(prisma);
}

export async function resolveGuildTier(prisma: PrismaClient, guildId: string): Promise<PremiumTier> {
  const assignment = await prisma.guildPremiumAssignment.findUnique({ where: { guildId } });
  if (!assignment || !isAssignmentActive(assignment.expiresAt)) {
    return 'FREE';
  }
  const parsed = PremiumTierSchema.safeParse(assignment.tier);
  return parsed.success ? parsed.data : 'FREE';
}

export async function resolveGuildPremiumConfig(
  prisma: PrismaClient,
  guildId: string
): Promise<PremiumTierConfig> {
  const tier = await resolveGuildTier(prisma, guildId);
  const configs = await ensurePremiumTierConfigs(prisma);
  return configs.find((config) => config.tier === tier) ?? DEFAULT_PREMIUM_TIER_CONFIGS[tier];
}

export async function assertPremiumLimit(
  prisma: PrismaClient,
  guildId: string,
  resource: PremiumLimitResource,
  currentCount: number
): Promise<PremiumTierConfig> {
  const config = await resolveGuildPremiumConfig(prisma, guildId);
  const featureKey = featureKeyForResource(resource);
  if (!config.features[featureKey]) {
    throw new PremiumLimitError('feature_disabled', resource, 0, currentCount, config.tier);
  }
  const limit = config[limitKeyForResource(resource)];
  if (currentCount >= limit) {
    throw new PremiumLimitError('limit_reached', resource, limit, currentCount, config.tier);
  }
  return config;
}
