import * as fs from 'fs';
import * as path from 'path';
import { prisma } from '@shieldai/db';
import {
  ReportType,
  ReportStatus,
  ReportDataPayload,
  GenerateReportInput,
  SecurityReportOutput,
} from '@shieldai/types';
import { collectAllReportData } from './data-collector';
import { htmlRenderer } from './html-renderer';
import { pdfGenerator } from './pdf-generator';

const PDF_STORAGE_DIR = process.env.PDF_STORAGE_DIR || path.join(process.cwd(), 'storage', 'reports', 'pdfs');

export class ReportService {
  async generateReport(input: GenerateReportInput): Promise<SecurityReportOutput> {
    const { userId, subscriptionId, reportType, periodStart, periodEnd } = input;

    const startDate = periodStart || this.getDefaultPeriodStart(reportType);
    const endDate = periodEnd || new Date();

    const title = this.generateTitle(reportType, startDate, endDate);

    const report = await prisma.securityReport.create({
      data: {
        userId,
        subscriptionId,
        reportType,
        status: ReportStatus.GENERATING,
        periodStart: startDate,
        periodEnd: endDate,
        title,
      },
    });

    try {
      const dataPayload = await collectAllReportData(
        userId,
        subscriptionId,
        reportType,
        startDate,
        endDate
      );

      const htmlContent = htmlRenderer.render({
        reportTitle: title,
        reportType,
        periodStart: startDate.toISOString(),
        periodEnd: endDate.toISOString(),
        generatedAt: new Date().toISOString(),
        userName: userId,
        data: dataPayload,
        dashboardUrl: `${process.env.DASHBOARD_URL || 'https://app.shieldai.com'}/reports/${report.id}`,
        reportId: report.id,
      });

      const pdfBuffer = await pdfGenerator.generate({
        reportTitle: title,
        periodStart: startDate.toISOString(),
        periodEnd: endDate.toISOString(),
        generatedAt: new Date().toISOString(),
        data: dataPayload,
        reportId: report.id,
      });

      const pdfUrl = this.storePdf(pdfBuffer, report.id);

      const summary = this.generateSummary(dataPayload);

      const updatedReport = await prisma.securityReport.update({
        where: { id: report.id },
        data: {
          status: ReportStatus.COMPLETED,
          htmlContent,
          pdfUrl,
          dataPayload: JSON.parse(JSON.stringify(dataPayload)),
          summary,
        },
      });

      return this.formatOutput(updatedReport);
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Report generation failed';
      await prisma.securityReport.update({
        where: { id: report.id },
        data: {
          status: ReportStatus.FAILED,
          error: message,
        },
      });

      return this.formatOutput(
        await prisma.securityReport.findUniqueOrThrow({ where: { id: report.id } })
      );
    }
  }

  async getReportHistory(userId: string, limit = 20, offset = 0): Promise<SecurityReportOutput[]> {
    const reports = await prisma.securityReport.findMany({
      where: { userId },
      orderBy: { createdAt: 'desc' },
      take: limit,
      skip: offset,
    });

    return reports.map((r) => this.formatOutput(r));
  }

  async getReportById(userId: string, reportId: string): Promise<SecurityReportOutput> {
    const report = await prisma.securityReport.findFirst({
      where: { id: reportId, userId },
    });

    if (!report) {
      throw new Error(`Report ${reportId} not found`);
    }

    return this.formatOutput(report);
  }

  async scheduleMonthlyReports(): Promise<string[]> {
    const plusSubscriptions = await prisma.subscription.findMany({
      where: {
        tier: 'plus',
        status: 'active',
      },
      select: {
        id: true,
        userId: true,
        user: { select: { email: true } },
      },
    });

    const createdIds: string[] = [];
    const now = new Date();
    const periodStart = new Date(now.getFullYear(), now.getMonth(), 1);
    const periodEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0);

    for (const sub of plusSubscriptions) {
      const existing = await prisma.securityReport.findFirst({
        where: {
          subscriptionId: sub.id,
          reportType: 'MONTHLY_PLUS',
          periodStart: periodStart,
        },
      });

      if (!existing) {
        const report = await prisma.securityReport.create({
          data: {
            userId: sub.userId,
            subscriptionId: sub.id,
            reportType: 'MONTHLY_PLUS',
            status: 'PENDING',
            periodStart,
            periodEnd,
            title: `Monthly Protection Report — ${periodStart.toLocaleDateString('en-US', { month: 'long', year: 'numeric' })}`,
            scheduledFor: new Date(now.getFullYear(), now.getMonth() + 1, 1),
          },
        });
        createdIds.push(report.id);
      }
    }

    return createdIds;
  }

  async scheduleAnnualReports(): Promise<string[]> {
    const premiumSubscriptions = await prisma.subscription.findMany({
      where: {
        tier: 'premium',
        status: 'active',
      },
      select: { id: true, userId: true, currentPeriodStart: true },
    });

    const createdIds: string[] = [];
    const now = new Date();

    for (const sub of premiumSubscriptions) {
      const anniversaryDate = new Date(sub.currentPeriodStart);
      anniversaryDate.setFullYear(anniversaryDate.getFullYear() + 1);

      const isDue =
        now >= anniversaryDate ||
        Math.abs(now.getTime() - anniversaryDate.getTime()) < 86400000 * 7;

      if (isDue) {
        const periodStart = new Date(sub.currentPeriodStart);
        const periodEnd = new Date(sub.currentPeriodStart);
        periodEnd.setFullYear(periodEnd.getFullYear() + 1);

        const existing = await prisma.securityReport.findFirst({
          where: {
            subscriptionId: sub.id,
            reportType: 'ANNUAL_PREMIUM',
            periodStart: periodStart,
          },
        });

        if (!existing) {
          const report = await prisma.securityReport.create({
            data: {
              userId: sub.userId,
              subscriptionId: sub.id,
              reportType: 'ANNUAL_PREMIUM',
              status: 'PENDING',
              periodStart,
              periodEnd,
              title: `Annual Protection Audit — ${periodStart.getFullYear()}`,
            },
          });
          createdIds.push(report.id);
        }
      }
    }

    return createdIds;
  }

  private getDefaultPeriodStart(reportType: ReportType): Date {
    const now = new Date();
    if (reportType === 'MONTHLY_PLUS') {
      return new Date(now.getFullYear(), now.getMonth() - 1, 1);
    }
    return new Date(now.getFullYear() - 1, now.getMonth(), now.getDate());
  }

  private generateTitle(
    reportType: ReportType,
    periodStart: Date,
    periodEnd: Date
  ): string {
    if (reportType === 'MONTHLY_PLUS') {
      return `Monthly Protection Report — ${periodStart.toLocaleDateString('en-US', {
        month: 'long',
        year: 'numeric',
      })}`;
    }
    return `Annual Protection Audit — ${periodStart.getFullYear()}`;
  }

  private generateSummary(data: ReportDataPayload): string {
    const parts: string[] = [];

    parts.push(
      `Protection Score: ${data.protectionScore}/100`
    );

    if (data.exposureSummary.newExposures > 0) {
      parts.push(
        `${data.exposureSummary.newExposures} new exposure(s) detected (${data.exposureSummary.criticalExposures} critical)`
      );
    }

    parts.push(
      `${data.spamStats.totalSpamEvents} spam event(s) blocked`
    );

    if (data.voiceStats.threatsDetected > 0) {
      parts.push(
        `${data.voiceStats.threatsDetected} voice threat(s) detected`
      );
    }

    return parts.join('. ');
  }

  private storePdf(pdfBuffer: Buffer, reportId: string): string {
    const pdfPath = path.join(PDF_STORAGE_DIR, `${reportId}.pdf`);

    const dir = path.dirname(pdfPath);
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }

    fs.writeFileSync(pdfPath, pdfBuffer);

    const dashboardUrl = process.env.DASHBOARD_URL || 'https://app.shieldai.com';
    return `${dashboardUrl}/api/v1/reports/${reportId}/pdf`;
  }

  private formatOutput(report: any): SecurityReportOutput {
    return {
      id: report.id,
      userId: report.userId,
      reportType: report.reportType,
      status: report.status,
      periodStart: report.periodStart,
      periodEnd: report.periodEnd,
      title: report.title,
      summary: report.summary,
      pdfUrl: report.pdfUrl,
      dataPayload: report.dataPayload ? JSON.parse(report.dataPayload) : undefined,
      error: report.error,
      createdAt: report.createdAt,
      deliveredAt: report.deliveredAt,
    };
  }
}

export const reportService = new ReportService();
