import { prisma } from '../../config/database';
import { redis } from '../../config/redis';
import { siteSettingsService } from '../settings/settings.service';
import { env } from '../../config/env';
import { logger } from '../../utils/logger';

const CACHE_KEY = 'homepage:public';
const CACHE_TTL = 120; // 2 minutes

interface HomepageData {
  featuredCampaigns: Array<{
    id: string;
    slug: string;
    title: string;
    description: string | null;
    emailCount: number;
    highlightCampaign: boolean;
  }>;
  upcomingShifts: Array<{
    id: string;
    title: string;
    startTime: string;
    endTime: string;
    location: string | null;
    currentVolunteers: number;
    maxVolunteers: number | null;
  }>;
  latestMedia: Array<{
    id: number;
    title: string | null;
    thumbnailPath: string | null;
    durationSeconds: number | null;
  }>;
  upcomingEvents: Array<{
    id: number;
    title: string;
    placeName: string;
    startDatetime: string;
    tags: string[];
  }>;
  stats: {
    totalEmailsSent: number;
    activeCampaigns: number;
    totalShiftSignups: number;
  };
  enabledModules: {
    influence: boolean;
    map: boolean;
    media: boolean;
    events: boolean;
    payments: boolean;
    landingPages: boolean;
  };
}

export const homepageService = {
  async getPublicData(): Promise<HomepageData> {
    // Check cache
    try {
      const cached = await redis.get(CACHE_KEY);
      if (cached) return JSON.parse(cached);
    } catch { /* cache miss */ }

    const settings = await siteSettingsService.getPublic();

    const enabledModules = {
      influence: settings.enableInfluence !== false,
      map: settings.enableMap !== false,
      media: settings.enableMediaFeatures !== false,
      events: settings.enableEvents !== false,
      payments: settings.enablePayments === true,
      landingPages: settings.enableLandingPages !== false,
    };

    // Fan-out with allSettled so one failure doesn't break the whole page
    const [
      campaignsResult,
      shiftsResult,
      mediaResult,
      eventsResult,
      statsResult,
    ] = await Promise.allSettled([
      enabledModules.influence ? this.getFeaturedCampaigns() : Promise.resolve([]),
      enabledModules.map ? this.getUpcomingShifts() : Promise.resolve([]),
      enabledModules.media ? this.getLatestMedia() : Promise.resolve([]),
      enabledModules.events ? this.getUpcomingEvents() : Promise.resolve([]),
      this.getStats(enabledModules),
    ]);

    const data: HomepageData = {
      featuredCampaigns: campaignsResult.status === 'fulfilled' ? campaignsResult.value : [],
      upcomingShifts: shiftsResult.status === 'fulfilled' ? shiftsResult.value : [],
      latestMedia: mediaResult.status === 'fulfilled' ? mediaResult.value : [],
      upcomingEvents: eventsResult.status === 'fulfilled' ? eventsResult.value : [],
      stats: statsResult.status === 'fulfilled' ? statsResult.value : { totalEmailsSent: 0, activeCampaigns: 0, totalShiftSignups: 0 },
      enabledModules,
    };

    // Cache
    try {
      await redis.setex(CACHE_KEY, CACHE_TTL, JSON.stringify(data));
    } catch { /* non-critical */ }

    return data;
  },

  async getFeaturedCampaigns() {
    // Highlighted first, then by email count
    const campaigns = await prisma.campaign.findMany({
      where: { status: 'ACTIVE' },
      select: {
        id: true,
        slug: true,
        title: true,
        description: true,
        highlightCampaign: true,
        _count: { select: { emails: true } },
      },
      orderBy: [{ highlightCampaign: 'desc' }, { createdAt: 'desc' }],
      take: 3,
    });

    return campaigns.map(c => ({
      id: c.id,
      slug: c.slug,
      title: c.title,
      description: c.description ? c.description.slice(0, 200) : null,
      emailCount: c._count.emails,
      highlightCampaign: c.highlightCampaign,
    }));
  },

  async getUpcomingShifts() {
    const today = new Date();
    today.setHours(0, 0, 0, 0);

    const shifts = await prisma.shift.findMany({
      where: {
        date: { gte: today },
        status: 'OPEN',
      },
      select: {
        id: true,
        title: true,
        date: true,
        startTime: true,
        endTime: true,
        location: true,
        maxVolunteers: true,
        _count: { select: { signups: true } },
      },
      orderBy: { date: 'asc' },
      take: 3,
    });

    return shifts.map(s => ({
      id: s.id,
      title: s.title,
      startTime: `${s.date.toISOString().split('T')[0]}T${s.startTime}:00`,
      endTime: `${s.date.toISOString().split('T')[0]}T${s.endTime}:00`,
      location: s.location,
      currentVolunteers: s._count.signups,
      maxVolunteers: s.maxVolunteers,
    }));
  },

  async getLatestMedia() {
    try {
      const videos = await prisma.video.findMany({
        where: { isPublished: true },
        select: {
          id: true,
          title: true,
          thumbnailPath: true,
          durationSeconds: true,
        },
        orderBy: { publishedAt: 'desc' },
        take: 4,
      });

      return videos.map(v => ({
        id: v.id,
        title: v.title,
        thumbnailPath: v.thumbnailPath,
        durationSeconds: v.durationSeconds,
      }));
    } catch {
      // Video table may not exist
      return [];
    }
  },

  async getUpcomingEvents() {
    try {
      const url = `${env.GANCIO_URL}/api/events`;
      const fetchRes = await fetch(url, { signal: AbortSignal.timeout(5000) });
      if (!fetchRes.ok) return [];

      const rawEvents = await fetchRes.json() as Array<{
        id: number;
        title: string;
        place_name: string;
        start_datetime: number;
        tags: string[];
      }>;

      const nowUnix = Math.floor(Date.now() / 1000);
      return rawEvents
        .filter(e => e.start_datetime >= nowUnix)
        .sort((a, b) => a.start_datetime - b.start_datetime)
        .slice(0, 3)
        .map(e => ({
          id: e.id,
          title: e.title,
          placeName: e.place_name || '',
          startDatetime: new Date(e.start_datetime * 1000).toISOString(),
          tags: Array.isArray(e.tags) ? e.tags : [],
        }));
    } catch {
      return [];
    }
  },

  async getStats(modules: { influence: boolean; map: boolean }) {
    const [emailCount, campaignCount, signupCount] = await Promise.allSettled([
      modules.influence
        ? prisma.campaignEmail.count()
        : Promise.resolve(0),
      modules.influence
        ? prisma.campaign.count({ where: { status: 'ACTIVE' } })
        : Promise.resolve(0),
      modules.map
        ? prisma.shiftSignup.count()
        : Promise.resolve(0),
    ]);

    return {
      totalEmailsSent: emailCount.status === 'fulfilled' ? emailCount.value : 0,
      activeCampaigns: campaignCount.status === 'fulfilled' ? campaignCount.value : 0,
      totalShiftSignups: signupCount.status === 'fulfilled' ? signupCount.value : 0,
    };
  },
};
