import { NextRequest, NextResponse } from 'next/server';
import { resolveCrmAccess } from '@/features/crm/reports/server/context';
import {
  auditReportExport,
  buildReportCsv,
  buildReportExcel
} from '@/features/crm/reports/server/exports/service';
import { parseSharedReportFilters } from '@/features/crm/reports/server/filters/shared';
import {
  getCrmOpportunityAgingReportResponse,
  getCrmLeadAgingReportResponse,
  getCrmPipelineReportResponse
} from '@/features/crm/reports/server/service';
import { PERMISSIONS } from '@/lib/auth/rbac';
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';

function buildExportRows(input: {
  reportCode: string;
  pipeline?: Awaited<ReturnType<typeof getCrmPipelineReportResponse>>;
  leadAging?: Awaited<ReturnType<typeof getCrmLeadAgingReportResponse>>;
  opportunityAging?: Awaited<ReturnType<typeof getCrmOpportunityAgingReportResponse>>;
}) {
  switch (input.reportCode) {
    case 'lead_pipeline':
      return [
        ['Lead Source', 'Customer Owner', 'Created By', 'Branch', 'Product Type', 'Total Leads', 'New Leads', 'Assigned Leads', 'Unassigned Leads', 'Converted Leads'],
        ...(input.pipeline?.leadPipeline ?? []).map((row) => [
          row.leadSourceLabel,
          row.customerOwnerName,
          row.createdByName,
          row.branchLabel,
          row.productTypeLabel,
          String(row.totalLeads),
          String(row.newLeads),
          String(row.assignedLeads),
          String(row.unassignedLeads),
          String(row.convertedLeads)
        ])
      ];
    case 'opportunity_pipeline':
      return [
        ['Salesman', 'Branch', 'Product Type', 'Customer Owner', 'Open Opportunities', 'Converted To Quotation', 'Won', 'Lost'],
        ...(input.pipeline?.opportunityPipeline ?? []).map((row) => [
          row.salesmanName,
          row.branchLabel,
          row.productTypeLabel,
          row.customerOwnerName,
          String(row.openOpportunities),
          String(row.convertedToQuotation),
          String(row.won),
          String(row.lost)
        ])
      ];
    case 'lead_conversion':
      return [
        ['Lead Source', 'Branch', 'Product Type', 'Marketing User', 'Total Leads', 'Converted Opportunities', 'Conversion Rate %'],
        ...(input.pipeline?.leadConversion ?? []).map((row) => [
          row.leadSourceLabel,
          row.branchLabel,
          row.productTypeLabel,
          row.marketingUserName,
          String(row.totalLeads),
          String(row.convertedOpportunities),
          String(row.conversionRate)
        ])
      ];
    case 'opportunity_conversion':
      return [
        ['Salesman', 'Branch', 'Product Type', 'Total Opportunities', 'Opportunities With Quotation', 'Conversion Rate %'],
        ...(input.pipeline?.opportunityConversion ?? []).map((row) => [
          row.salesmanName,
          row.branchLabel,
          row.productTypeLabel,
          String(row.totalOpportunities),
          String(row.opportunitiesWithQuotation),
          String(row.conversionRate)
        ])
      ];
    case 'pipeline_funnel':
      return [
        ['Stage', 'Count', 'Value', 'Conversion Rate %'],
        ...(input.pipeline?.funnel ?? []).map((row) => [
          row.stageLabel,
          String(row.count),
          row.value === null ? '' : String(row.value),
          row.conversionRate === null ? '' : String(row.conversionRate)
        ])
      ];
    case 'lead_aging':
      return [
        ['Lead Number', 'Customer', 'Assigned User', 'Created Date', 'Aging Days'],
        ...(input.leadAging?.rows ?? []).map((row) => [
          row.leadCode,
          row.customerName,
          row.assignedUserName ?? '',
          row.createdDate,
          String(row.agingDays)
        ])
      ];
    case 'opportunity_aging':
      return [
        ['Opportunity No', 'Customer', 'Salesman', 'Last Follow-Up', 'Aging Days'],
        ...(input.opportunityAging?.rows ?? []).map((row) => [
          row.opportunityCode,
          row.customerName,
          row.salesmanName ?? '',
          row.lastFollowupDate ?? '',
          String(row.agingDays)
        ])
      ];
    default:
      return null;
  }
}

function getRecordCount(input: {
  reportCode: string;
  pipeline?: Awaited<ReturnType<typeof getCrmPipelineReportResponse>>;
  leadAging?: Awaited<ReturnType<typeof getCrmLeadAgingReportResponse>>;
  opportunityAging?: Awaited<ReturnType<typeof getCrmOpportunityAgingReportResponse>>;
}) {
  switch (input.reportCode) {
    case 'lead_pipeline':
      return input.pipeline?.leadPipeline.length ?? 0;
    case 'opportunity_pipeline':
      return input.pipeline?.opportunityPipeline.length ?? 0;
    case 'lead_conversion':
      return input.pipeline?.leadConversion.length ?? 0;
    case 'opportunity_conversion':
      return input.pipeline?.opportunityConversion.length ?? 0;
    case 'pipeline_funnel':
      return input.pipeline?.funnel.length ?? 0;
    case 'lead_aging':
      return input.leadAging?.rows.length ?? 0;
    case 'opportunity_aging':
      return input.opportunityAging?.rows.length ?? 0;
    default:
      return 0;
  }
}

export async function GET(request: NextRequest) {
  try {
    const { organization, session, membership } = await requireOrganizationAccess({
      permission: PERMISSIONS.crmReportExport
    });
    const reportCode = request.nextUrl.searchParams.get('reportCode') ?? '';
    const format = request.nextUrl.searchParams.get('format') === 'xls' ? 'xls' : 'csv';
    const filters = parseSharedReportFilters(request.nextUrl.searchParams);
    const context = resolveCrmAccess({
      organizationId: organization.id,
      userId: session.user.id,
      membership
    });

    const pipelineCodes = new Set([
      'lead_pipeline',
      'opportunity_pipeline',
      'lead_conversion',
      'opportunity_conversion',
      'pipeline_funnel'
    ]);
    const pipeline = pipelineCodes.has(reportCode)
      ? await getCrmPipelineReportResponse(context, filters)
      : undefined;
    const leadAging =
      reportCode === 'lead_aging' ? await getCrmLeadAgingReportResponse(context, filters) : undefined;
    const opportunityAging =
      reportCode === 'opportunity_aging'
        ? await getCrmOpportunityAgingReportResponse(context, filters)
        : undefined;
    const rows = buildExportRows({ reportCode, pipeline, leadAging, opportunityAging });

    if (!rows) {
      return NextResponse.json({ message: 'Unsupported report code' }, { status: 400 });
    }

    const body = format === 'xls' ? buildReportExcel(rows) : buildReportCsv(rows);
    const extension = format === 'xls' ? 'xls' : 'csv';
    const contentType =
      format === 'xls' ? 'application/vnd.ms-excel; charset=utf-8' : 'text/csv; charset=utf-8';

    await auditReportExport({
      organizationId: organization.id,
      userId: session.user.id,
      reportCode,
      format,
      filters: { ...filters },
      recordCount: getRecordCount({ reportCode, pipeline, leadAging, opportunityAging })
    });

    return new NextResponse(body, {
      headers: {
        'Content-Type': contentType,
        'Content-Disposition': `attachment; filename="crm-report-${reportCode}.${extension}"`
      }
    });
  } catch (error) {
    if (error instanceof AuthError) {
      return NextResponse.json({ message: error.message }, { status: error.status });
    }

    return NextResponse.json({ message: 'Unable to export CRM report' }, { status: 500 });
  }
}

