import { NextRequest, NextResponse } from 'next/server';
import Papa from 'papaparse';
import { db } from '@/lib/db';
import { candles, charts } from '@/lib/db/schema';
import { eq, like } from 'drizzle-orm';

async function getUniqueChartName(baseName: string): Promise<string> {
  // Check if the base name is already taken
  const existing = await db.select().from(charts).where(eq(charts.name, baseName)).limit(1);
  if (existing.length === 0) return baseName;

  // Find existing charts with this base name pattern (e.g., "btc-daily-2", "btc-daily-3")
  const pattern = `${baseName}-%`;
  const suffixed = await db.select({ name: charts.name }).from(charts).where(like(charts.name, pattern));

  let maxSuffix = 1;
  for (const row of suffixed) {
    const match = row.name.match(/-(\d+)$/);
    if (match) {
      maxSuffix = Math.max(maxSuffix, parseInt(match[1], 10));
    }
  }

  return `${baseName}-${maxSuffix + 1}`;
}

export async function POST(request: NextRequest): Promise<NextResponse> {
  try {
    const formData = await request.formData();
    const file = formData.get('file') as File;

    if (!file) {
      return NextResponse.json(
        { error: 'No file provided' },
        { status: 400 }
      );
    }

    // Validate file type
    const fileName = file.name.toLowerCase();
    if (!fileName.endsWith('.csv')) {
      return NextResponse.json(
        { error: 'Invalid file type. Only CSV files are accepted.' },
        { status: 400 }
      );
    }

    const mimeType = file.type;
    const isValidMimeType = mimeType.startsWith('text/') || mimeType === 'application/csv' || mimeType === 'text/csv';
    if (!isValidMimeType) {
      return NextResponse.json(
        { error: 'Invalid file type. Only CSV files are accepted.' },
        { status: 400 }
      );
    }

    const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
    if (file.size > MAX_FILE_SIZE) {
      return NextResponse.json(
        { error: 'File too large. Maximum size is 10MB.' },
        { status: 400 }
      );
    }

    const text = await file.text();

    // Derive chart name from filename (strip .csv extension)
    const baseName = file.name.replace(/\.csv$/i, '');

    return new Promise<NextResponse>((resolve) => {
      Papa.parse(text, {
        header: true,
        dynamicTyping: true,
        skipEmptyLines: true,
        complete: async (results) => {
          try {
            const rows = results.data as any[];

            // Validate row count
            const MAX_ROWS = 500000;
            if (rows.length > MAX_ROWS) {
              resolve(
                NextResponse.json(
                  { error: 'File contains too many rows. Maximum is 500,000.' },
                  { status: 400 }
                )
              );
              return;
            }

            // Validate headers
            if (rows.length === 0) {
              resolve(
                NextResponse.json(
                  { error: 'CSV file is empty' },
                  { status: 400 }
                )
              );
              return;
            }

            const firstRow = rows[0];
            const requiredHeaders = ['time', 'open', 'high', 'low', 'close'];
            const missingHeaders = requiredHeaders.filter(
              (header) => !(header in firstRow)
            );

            if (missingHeaders.length > 0) {
              resolve(
                NextResponse.json(
                  {
                    error: `Missing required headers: ${missingHeaders.join(', ')}`,
                  },
                  { status: 400 }
                )
              );
              return;
            }

            // Get unique chart name (handle duplicates)
            const chartName = await getUniqueChartName(baseName);

            // Create the chart
            const [newChart] = await db.insert(charts).values({
              name: chartName,
            }).returning();

            // Parse and prepare candle data
            const candleData = rows.map((row) => {
              let timestamp: Date;

              // Handle both date strings and Unix timestamps
              if (typeof row.time === 'string') {
                // Try parsing as date string
                const date = new Date(row.time);
                if (isNaN(date.getTime())) {
                  throw new Error(`Invalid date format: ${row.time}`);
                }
                timestamp = date;
              } else if (typeof row.time === 'number') {
                // If Unix timestamp (seconds), convert to Date
                timestamp = new Date(row.time * 1000);
              } else {
                throw new Error(`Invalid time value: ${row.time}`);
              }

              return {
                chart_id: newChart.id,
                time: timestamp,
                open: Number(row.open),
                high: Number(row.high),
                low: Number(row.low),
                close: Number(row.close),
              };
            });

            // Insert candles for this chart
            const count = candleData.length;
            if (count > 0) {
              await db.insert(candles).values(candleData);
            }

            resolve(
              NextResponse.json({
                success: true,
                count,
                chart: { id: newChart.id, name: newChart.name },
              })
            );
          } catch (error: any) {
            console.error(error);
            resolve(
              NextResponse.json(
                { error: 'Internal server error' },
                { status: 500 }
              )
            );
          }
        },
        error: (error: any) => {
          console.error(error);
          resolve(
            NextResponse.json(
              { error: 'Internal server error' },
              { status: 500 }
            )
          );
        },
      });
    });
  } catch (error: any) {
    console.error(error);
    return NextResponse.json(
      { error: 'Internal server error' },
      { status: 500 }
    );
  }
}
