import { NextRequest, NextResponse } from 'next/server';
import { getDb } from '@/lib/db';
import { generateSessionCode } from '@/lib/session-code';
import { geocodeCity } from '@/lib/geocode';
import { randomUUID } from 'crypto';
import { createSessionSchema, parseBody } from '@/lib/validation';
import type Database from 'better-sqlite3';

function insertSessionWithUniqueCode(
  db: Database.Database,
  insertSession: Database.Statement,
  baseParams: Record<string, unknown>,
): { code: string; result: Database.RunResult } {
  for (let attempt = 0; attempt < 10; attempt++) {
    const code = generateSessionCode();
    try {
      const result = insertSession.run({ ...baseParams, code });
      return { code, result };
    } catch (e: any) {
      // Kollision bei paralleler Code-Erzeugung -> erneut versuchen.
      if (e.message?.includes('UNIQUE constraint failed: sessions.code')) continue;
      throw e;
    }
  }
  throw new Error('Konnte keinen eindeutigen Session-Code erzeugen');
}

export async function POST(req: NextRequest) {
  const parsed = await parseBody(req, createSessionSchema);
  if (!parsed.success) return parsed.response;

  const {
    city, postalCode, lat, lon, radiusKm,
    dietFilter, cuisineTags, priceMin, priceMax,
    excludeFastFood, excludeChains, openNowOnly,
    displayName,
  } = parsed.data;

  let resolvedLat = lat;
  let resolvedLon = lon;
  if ((!resolvedLat || !resolvedLon) && city) {
    const geo = await geocodeCity(`${city}${postalCode ? ', ' + postalCode : ''}`);
    if (geo) {
      resolvedLat = geo.lat;
      resolvedLon = geo.lon;
    }
  }

  const db = getDb();

  const insertSession = db.prepare(`
    INSERT INTO sessions
      (code, city, postal_code, lat, lon, radius_km, diet_filter, cuisine_tags,
       price_min, price_max, exclude_fast_food, exclude_chains, open_now_only)
    VALUES (@code, @city, @postalCode, @lat, @lon, @radiusKm, @dietFilter, @cuisineTags,
       @priceMin, @priceMax, @excludeFastFood, @excludeChains, @openNowOnly)
  `);

  const baseParams = {
    city, postalCode: postalCode ?? null, lat: resolvedLat ?? null, lon: resolvedLon ?? null,
    radiusKm, dietFilter: dietFilter ?? null, cuisineTags: JSON.stringify(cuisineTags),
    priceMin, priceMax, excludeFastFood: excludeFastFood ? 1 : 0, excludeChains: excludeChains ? 1 : 0,
    openNowOnly: openNowOnly ? 1 : 0,
  };

  const { code, result } = insertSessionWithUniqueCode(db, insertSession, baseParams);

  const sessionId = result.lastInsertRowid;
  const anonymousId = randomUUID();

  const participant = db.prepare(`
    INSERT INTO participants (session_id, anonymous_id, display_name, is_creator)
    VALUES (?, ?, ?, 1)
  `).run(sessionId, anonymousId, displayName ?? null);

  db.prepare('UPDATE sessions SET created_by_participant_id = ? WHERE id = ?')
    .run(participant.lastInsertRowid, sessionId);

  return NextResponse.json({ code, sessionId, anonymousId, participantId: participant.lastInsertRowid });
}
