import { Prisma, TicketedEventStatus, ShiftKind, ShiftStatus, SignupStatus, TicketStatus } from '@prisma/client';
import { prisma } from '../../config/database';
import { env } from '../../config/env';
import { actionCampaignsService, type ActiveCampaignForUser } from '../action-campaigns/action-campaigns.service';
import { referralService } from '../social/referral.service';

export interface DashboardProfile {
  id: string;
  email: string;
  name: string | null;
  avatar: string | null;
  role: string;
}

export interface DashboardReferral {
  code: string | null;
  link: string | null;
  totalReferrals: number;
}

export interface DashboardFeaturedEvent {
  slug: string;
  title: string;
  date: Date;
  startTime: string;
  venueName: string | null;
  coverImageUrl: string | null;
  ticketsSold: number;
  maxAttendees: number | null;
}

export interface DashboardTraining {
  id: string;
  title: string;
  date: Date;
  startTime: string;
  endTime: string;
  location: string | null;
  currentVolunteers: number;
  maxVolunteers: number;
  isSignedUp: boolean;
  signupId: string | null;
}

export interface DashboardMyEvent {
  ticketId: string;
  eventSlug: string;
  eventTitle: string;
  eventDate: Date;
  status: TicketStatus;
  tierName: string;
}

export interface DashboardPoints {
  total: number;
  achievementCount: number;
}

export type DashboardResourceKind = 'document' | 'video' | 'photo';

export interface DashboardResource {
  id: string;
  kind: DashboardResourceKind;
  title: string;
  thumbnailUrl: string | null;
  downloadPath: string | null;
  viewPath: string | null;
}

export interface VolunteerDashboardPayload {
  profile: DashboardProfile;
  referral: DashboardReferral;
  actionCampaign: ActiveCampaignForUser | null;
  featuredEvent: DashboardFeaturedEvent | null;
  trainings: DashboardTraining[];
  myEvents: DashboardMyEvent[];
  points: DashboardPoints;
  resources: DashboardResource[];
}

const RESOURCE_TAG = 'volunteer-resource';

async function getProfile(userId: string): Promise<DashboardProfile | null> {
  const user = await prisma.user.findUnique({
    where: { id: userId },
    select: { id: true, email: true, name: true, role: true },
  });
  if (!user) return null;
  return {
    id: user.id,
    email: user.email,
    name: user.name,
    avatar: null,
    role: user.role,
  };
}

async function getReferral(userId: string): Promise<DashboardReferral> {
  const stats = await referralService.getReferralStats(userId);
  let firstCode = await prisma.inviteCode.findFirst({
    where: { createdByUserId: userId, isActive: true },
    orderBy: { createdAt: 'desc' },
    select: { code: true },
  });
  if (!firstCode) {
    const created = await referralService.createInviteCode(userId, {});
    firstCode = { code: created.code };
  }
  const code = firstCode.code;
  const link = `${env.ADMIN_URL}/register?ref=${code}`;
  return { code, link, totalReferrals: stats.totalReferrals };
}

async function getFeaturedEvent(): Promise<DashboardFeaturedEvent | null> {
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  const eventSelect = {
    slug: true,
    title: true,
    date: true,
    startTime: true,
    venueName: true,
    coverImageUrl: true,
    currentAttendees: true,
    maxAttendees: true,
  } as const;
  const baseWhere = { status: TicketedEventStatus.PUBLISHED, date: { gte: today } };

  // Prefer admin-featured event; fall back to next upcoming published event
  const event =
    await prisma.ticketedEvent.findFirst({
      where: { ...baseWhere, featured: true },
      orderBy: { date: 'asc' },
      select: eventSelect,
    }) ??
    await prisma.ticketedEvent.findFirst({
      where: baseWhere,
      orderBy: { date: 'asc' },
      select: eventSelect,
    });

  if (!event) return null;
  return {
    slug: event.slug,
    title: event.title,
    date: event.date,
    startTime: event.startTime,
    venueName: event.venueName,
    coverImageUrl: event.coverImageUrl,
    ticketsSold: event.currentAttendees,
    maxAttendees: event.maxAttendees,
  };
}

async function getTrainings(userId: string): Promise<DashboardTraining[]> {
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  const shifts = await prisma.shift.findMany({
    where: {
      kind: ShiftKind.TRAINING,
      status: ShiftStatus.OPEN,
      date: { gte: today },
    },
    orderBy: { date: 'asc' },
    take: 5,
    include: {
      signups: {
        where: { userId },
        select: { id: true },
      },
    },
  });

  return shifts.map((shift) => ({
    id: shift.id,
    title: shift.title,
    date: shift.date,
    startTime: shift.startTime,
    endTime: shift.endTime,
    location: shift.location,
    currentVolunteers: shift.currentVolunteers,
    maxVolunteers: shift.maxVolunteers,
    isSignedUp: shift.signups.length > 0,
    signupId: shift.signups[0]?.id ?? null,
  }));
}

async function getMyEvents(userId: string): Promise<DashboardMyEvent[]> {
  const tickets = await prisma.ticket.findMany({
    where: { userId, status: TicketStatus.VALID },
    take: 5,
    orderBy: { event: { date: 'asc' } },
    include: {
      event: { select: { slug: true, title: true, date: true } },
      tier: { select: { name: true } },
    },
  });

  return tickets.map((ticket) => ({
    ticketId: ticket.id,
    eventSlug: ticket.event.slug,
    eventTitle: ticket.event.title,
    eventDate: ticket.event.date,
    status: ticket.status,
    tierName: ticket.tier.name,
  }));
}

async function getPoints(userId: string): Promise<DashboardPoints> {
  const user = await prisma.user.findUnique({ where: { id: userId }, select: { email: true } });
  const email = user?.email ?? '';

  const [shiftSignups, campaignEmails, petitionSignatures, eventTickets, stepCompletions, achievementCount] =
    await Promise.all([
      prisma.shiftSignup.count({ where: { userId, status: SignupStatus.CONFIRMED } }),
      prisma.campaignEmail.count({ where: { userId } }),
      prisma.petitionSignature.count({ where: { signerEmail: email, verifiedAt: { not: null } } }),
      prisma.ticket.count({ where: { userId, status: TicketStatus.VALID } }),
      prisma.actionStepCompletion.count({ where: { userId } }),
      prisma.userAchievement.count({ where: { userId } }),
    ]);

  const total =
    shiftSignups * 10 +
    campaignEmails * 5 +
    petitionSignatures * 5 +
    eventTickets * 10 +
    stepCompletions * 5 +
    achievementCount * 15;

  return { total, achievementCount };
}

async function getResources(): Promise<DashboardResource[]> {
  const tagFilter = { tags: { array_contains: RESOURCE_TAG } as Prisma.JsonFilter };

  const [documents, videos, photos] = await Promise.all([
    prisma.document.findMany({
      where: { isPublished: true, ...tagFilter },
      orderBy: { createdAt: 'desc' },
      take: 8,
      select: {
        id: true,
        title: true,
        originalFilename: true,
        filename: true,
        thumbnailPath: true,
      },
    }),
    prisma.video.findMany({
      where: { isPublished: true, ...tagFilter },
      orderBy: { createdAt: 'desc' },
      take: 8,
      select: {
        id: true,
        title: true,
        filename: true,
        thumbnailPath: true,
      },
    }),
    prisma.photo.findMany({
      where: { isPublished: true, ...tagFilter },
      orderBy: { createdAt: 'desc' },
      take: 8,
      select: {
        id: true,
        title: true,
        filename: true,
        thumbnailPath: true,
      },
    }),
  ]);

  const items: Array<DashboardResource & { sortKey: number }> = [];

  for (const doc of documents) {
    items.push({
      id: doc.id,
      kind: 'document',
      title: doc.title ?? doc.originalFilename ?? doc.filename,
      thumbnailUrl: doc.thumbnailPath,
      downloadPath: `/api/documents/${doc.id}/download`,
      viewPath: null,
      sortKey: documents.indexOf(doc),
    });
  }
  for (const video of videos) {
    items.push({
      id: String(video.id),
      kind: 'video',
      title: video.title ?? video.filename,
      thumbnailUrl: video.thumbnailPath,
      downloadPath: null,
      viewPath: `/gallery/watch/${video.id}`,
      sortKey: videos.indexOf(video),
    });
  }
  for (const photo of photos) {
    items.push({
      id: String(photo.id),
      kind: 'photo',
      title: photo.title ?? photo.filename,
      thumbnailUrl: photo.thumbnailPath,
      downloadPath: null,
      viewPath: `/gallery/photo/${photo.id}`,
      sortKey: photos.indexOf(photo),
    });
  }

  items.sort((a, b) => a.sortKey - b.sortKey);
  return items.slice(0, 8).map(({ sortKey: _sortKey, ...rest }) => rest);
}

export const volunteerDashboardService = {
  async getDashboard(userId: string): Promise<VolunteerDashboardPayload | null> {
    const profile = await getProfile(userId);
    if (!profile) return null;

    const [referral, actionCampaign, featuredEvent, trainings, myEvents, points, resources] = await Promise.all([
      getReferral(userId),
      actionCampaignsService.getActiveForUser(userId),
      getFeaturedEvent(),
      getTrainings(userId),
      getMyEvents(userId),
      getPoints(userId),
      getResources(),
    ]);

    return {
      profile,
      referral,
      actionCampaign,
      featuredEvent,
      trainings,
      myEvents,
      points,
      resources,
    };
  },
};
