import { prisma } from '../../config/database';
import { SpotlightStatus } from '@prisma/client';
import { notificationService } from './notification.service';
import { achievementsService } from './achievements.service';
import { logger } from '../../utils/logger';
import { AppError } from '../../middleware/error-handler';

export const spotlightService = {
  /** Admin: nominate a volunteer for spotlight */
  async nominate(
    data: { userId: string; headline?: string; story?: string },
    nominatedByUserId: string,
  ) {
    // Verify the user exists
    const user = await prisma.user.findUnique({ where: { id: data.userId } });
    if (!user) throw new AppError(404, 'User not found', 'USER_NOT_FOUND');

    const spotlight = await prisma.volunteerSpotlight.create({
      data: {
        userId: data.userId,
        status: SpotlightStatus.NOMINATED,
        headline: data.headline,
        story: data.story,
        nominatedByUserId,
      },
      include: { user: { select: { id: true, name: true, email: true } } },
    });

    logger.info(`Volunteer ${data.userId} nominated for spotlight by ${nominatedByUserId}`);
    return spotlight;
  },

  /** Admin: approve a nomination */
  async approve(id: string, approvedByUserId: string) {
    const spotlight = await prisma.volunteerSpotlight.findUnique({ where: { id } });
    if (!spotlight) throw new AppError(404, 'Spotlight not found', 'SPOTLIGHT_NOT_FOUND');
    if (spotlight.status !== SpotlightStatus.NOMINATED) {
      throw new AppError(400, 'Only nominated spotlights can be approved', 'INVALID_STATUS');
    }

    const updated = await prisma.volunteerSpotlight.update({
      where: { id },
      data: {
        status: SpotlightStatus.APPROVED,
        approvedByUserId,
        approvedAt: new Date(),
      },
      include: { user: { select: { id: true, name: true, email: true } } },
    });

    await notificationService.createNotification(
      spotlight.userId,
      'achievement',
      'Spotlight Approved',
      'Your volunteer spotlight nomination has been approved!',
      { spotlightId: id },
    );

    return updated;
  },

  /** Admin: feature a spotlight for a specific month */
  async feature(id: string, month: string) {
    const spotlight = await prisma.volunteerSpotlight.findUnique({ where: { id } });
    if (!spotlight) throw new AppError(404, 'Spotlight not found', 'SPOTLIGHT_NOT_FOUND');
    if (spotlight.status !== SpotlightStatus.APPROVED) {
      throw new AppError(400, 'Only approved spotlights can be featured', 'INVALID_STATUS');
    }

    const updated = await prisma.volunteerSpotlight.update({
      where: { id },
      data: {
        status: SpotlightStatus.FEATURED,
        featuredMonth: month,
      },
      include: { user: { select: { id: true, name: true, email: true } } },
    });

    await notificationService.createNotification(
      spotlight.userId,
      'achievement',
      'You\'re Featured!',
      `You have been featured as a Volunteer Spotlight for ${month}!`,
      { spotlightId: id, featuredMonth: month },
    );

    logger.info(`Spotlight ${id} featured for ${month}`);
    return updated;
  },

  /** Admin: archive a spotlight */
  async archive(id: string) {
    const spotlight = await prisma.volunteerSpotlight.findUnique({ where: { id } });
    if (!spotlight) throw new AppError(404, 'Spotlight not found', 'SPOTLIGHT_NOT_FOUND');

    return prisma.volunteerSpotlight.update({
      where: { id },
      data: { status: SpotlightStatus.ARCHIVED },
      include: { user: { select: { id: true, name: true, email: true } } },
    });
  },

  /** Admin: update headline/story */
  async update(id: string, data: { headline?: string; story?: string }) {
    const spotlight = await prisma.volunteerSpotlight.findUnique({ where: { id } });
    if (!spotlight) throw new AppError(404, 'Spotlight not found', 'SPOTLIGHT_NOT_FOUND');

    return prisma.volunteerSpotlight.update({
      where: { id },
      data,
      include: { user: { select: { id: true, name: true, email: true } } },
    });
  },

  /** Admin: delete a spotlight */
  async delete(id: string) {
    const spotlight = await prisma.volunteerSpotlight.findUnique({ where: { id } });
    if (!spotlight) throw new AppError(404, 'Spotlight not found', 'SPOTLIGHT_NOT_FOUND');

    await prisma.volunteerSpotlight.delete({ where: { id } });
    return { success: true };
  },

  /** Admin: list all spotlights (paginated, filterable) */
  async listAll(page: number, limit: number, status?: SpotlightStatus) {
    const where = status ? { status } : {};
    const skip = (page - 1) * limit;

    const [spotlights, total] = await Promise.all([
      prisma.volunteerSpotlight.findMany({
        where,
        orderBy: { createdAt: 'desc' },
        skip,
        take: limit,
        include: {
          user: { select: { id: true, name: true, email: true } },
          nominatedBy: { select: { id: true, name: true } },
          approvedBy: { select: { id: true, name: true } },
        },
      }),
      prisma.volunteerSpotlight.count({ where }),
    ]);

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

  /** Public: get currently featured spotlights (this month) */
  async getCurrentFeatured() {
    const now = new Date();
    const currentMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;

    return prisma.volunteerSpotlight.findMany({
      where: {
        status: SpotlightStatus.FEATURED,
        featuredMonth: currentMonth,
      },
      include: {
        user: { select: { id: true, name: true } },
      },
      orderBy: { createdAt: 'desc' },
    });
  },

  /** Public: get leaderboard filtered by showOnLeaderboard privacy setting */
  async getPublicLeaderboard(type: 'canvass' | 'shifts' | 'campaigns', limit: number) {
    // Get a larger set from achievements service, then filter by privacy
    const entries = await achievementsService.getLeaderboard(type, limit * 3);

    if (entries.length === 0) return [];

    // Filter by showOnLeaderboard
    const userIds = entries.map((e) => e.userId);
    const hiddenIds = new Set(
      (await prisma.privacySettings.findMany({
        where: {
          userId: { in: userIds },
          showOnLeaderboard: false,
        },
        select: { userId: true },
      })).map((p) => p.userId),
    );

    const visible = entries
      .filter((e) => !hiddenIds.has(e.userId))
      .slice(0, limit)
      .map((e, i) => ({ ...e, rank: i + 1 }));

    return visible;
  },

  /** Public: wall of fame — all featured spotlights */
  async getWallOfFame(page: number, limit: number) {
    const skip = (page - 1) * limit;

    const [spotlights, total] = await Promise.all([
      prisma.volunteerSpotlight.findMany({
        where: { status: SpotlightStatus.FEATURED },
        orderBy: { featuredMonth: 'desc' },
        skip,
        take: limit,
        include: {
          user: { select: { id: true, name: true } },
        },
      }),
      prisma.volunteerSpotlight.count({ where: { status: SpotlightStatus.FEATURED } }),
    ]);

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

  /** User: get opt-in status for leaderboard */
  async getOptInStatus(userId: string) {
    const settings = await prisma.privacySettings.findUnique({
      where: { userId },
      select: { showOnLeaderboard: true },
    });
    return { showOnLeaderboard: settings?.showOnLeaderboard ?? true };
  },

  /** User: opt in to leaderboard */
  async optIn(userId: string) {
    await prisma.privacySettings.upsert({
      where: { userId },
      update: { showOnLeaderboard: true },
      create: { userId, showOnLeaderboard: true },
    });
    return { showOnLeaderboard: true };
  },

  /** User: opt out of leaderboard */
  async optOut(userId: string) {
    await prisma.privacySettings.upsert({
      where: { userId },
      update: { showOnLeaderboard: false },
      create: { userId, showOnLeaderboard: false },
    });
    return { showOnLeaderboard: false };
  },
};
