import { Prisma } from '@prisma/client';
import { prisma } from '../../config/database';
import { AppError } from '../../middleware/error-handler';

function generateSlug(name: string): string {
  return name
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '')
    .slice(0, 80);
}

async function resolveSlugCollision(slug: string, excludeId?: number): Promise<string> {
  let candidate = slug;
  let suffix = 2;

  while (true) {
    const existing = await prisma.subscriptionPlan.findUnique({
      where: { slug: candidate },
      select: { id: true },
    });

    if (!existing || (excludeId && existing.id === excludeId)) {
      return candidate;
    }

    candidate = `${slug}-${suffix}`;
    suffix++;
  }
}

export const plansService = {
  /** Admin: list plans with pagination, search, active filter */
  async findAll(filters: { page: number; limit: number; search?: string; isActive?: string }) {
    const { page, limit, search, isActive } = filters;
    const skip = (page - 1) * limit;

    const where: Prisma.SubscriptionPlanWhereInput = {};

    if (search) {
      where.OR = [
        { name: { contains: search, mode: 'insensitive' } },
        { description: { contains: search, mode: 'insensitive' } },
      ];
    }

    if (isActive === 'true') where.isActive = true;
    if (isActive === 'false') where.isActive = false;

    const [plans, total] = await Promise.all([
      prisma.subscriptionPlan.findMany({
        where,
        skip,
        take: limit,
        orderBy: { displayOrder: 'asc' },
        include: {
          _count: {
            select: {
              subscriptions: { where: { status: 'active' } },
            },
          },
        },
      }),
      prisma.subscriptionPlan.count({ where }),
    ]);

    return {
      plans,
      pagination: { page, limit, total, totalPages: Math.ceil(total / limit) },
    };
  },

  /** Admin: get single plan by ID */
  async findById(id: number) {
    const plan = await prisma.subscriptionPlan.findUnique({
      where: { id },
      include: {
        _count: {
          select: {
            subscriptions: { where: { status: 'active' } },
          },
        },
      },
    });

    if (!plan) {
      throw new AppError(404, 'Plan not found', 'PLAN_NOT_FOUND');
    }

    return plan;
  },

  /** Create plan with auto-generated slug */
  async create(data: Prisma.SubscriptionPlanUncheckedCreateInput) {
    const baseSlug = generateSlug(data.name);
    const slug = await resolveSlugCollision(baseSlug);

    // Enforce highlight exclusivity
    if (data.highlightPlan) {
      await prisma.subscriptionPlan.updateMany({
        where: { highlightPlan: true },
        data: { highlightPlan: false },
      });
    }

    return prisma.subscriptionPlan.create({
      data: {
        ...data,
        slug,
      },
    });
  },

  /** Update plan, regenerate slug if name changes */
  async update(id: number, data: Prisma.SubscriptionPlanUncheckedUpdateInput) {
    const existing = await prisma.subscriptionPlan.findUnique({ where: { id } });
    if (!existing) {
      throw new AppError(404, 'Plan not found', 'PLAN_NOT_FOUND');
    }

    const updateData: Prisma.SubscriptionPlanUncheckedUpdateInput = { ...data };

    // Regenerate slug if name changes
    if (typeof data.name === 'string' && data.name !== existing.name) {
      const baseSlug = generateSlug(data.name);
      updateData.slug = await resolveSlugCollision(baseSlug, id);
    }

    // Enforce highlight exclusivity
    if (data.highlightPlan === true) {
      await prisma.subscriptionPlan.updateMany({
        where: { highlightPlan: true, id: { not: id } },
        data: { highlightPlan: false },
      });
    }

    return prisma.subscriptionPlan.update({
      where: { id },
      data: updateData,
    });
  },

  /** Delete plan (blocked if active subscriptions exist) */
  async delete(id: number) {
    const activeSubs = await prisma.userSubscription.count({
      where: { planId: id, status: 'active' },
    });
    if (activeSubs > 0) {
      throw new Error(`Cannot delete plan with ${activeSubs} active subscriptions`);
    }
    return prisma.subscriptionPlan.delete({ where: { id } });
  },

  /** Public: list active plans for pricing page */
  async listActivePlans(limit: number = 50) {
    return prisma.subscriptionPlan.findMany({
      where: { isActive: true },
      orderBy: [
        { highlightPlan: 'desc' },
        { displayOrder: 'asc' },
      ],
      take: limit,
    });
  },

  /** Public: find active plan by slug for detail page */
  async findBySlugPublic(slug: string) {
    const plan = await prisma.subscriptionPlan.findUnique({
      where: { slug },
    });

    if (!plan) {
      throw new AppError(404, 'Plan not found', 'PLAN_NOT_FOUND');
    }

    if (!plan.isActive) {
      throw new AppError(404, 'Plan not found', 'PLAN_NOT_FOUND');
    }

    // Get active subscriber count
    const activeSubscribers = await prisma.userSubscription.count({
      where: { planId: plan.id, status: 'active' },
    });

    return { ...plan, activeSubscribers };
  },
};
