import { NextResponse } from 'next/server';
import { withErrorHandler } from '@server/middleware/withErrorHandler';
import { withAuth, requireSection, AuthedRequest } from '@server/middleware/withAuth';
import { db, restaurants } from '@server/db/drizzle';
import { eq, sql, type SQL } from 'drizzle-orm';
import { initDatabase } from '@server/db/init';

export const GET = withErrorHandler(
  withAuth(async (req: AuthedRequest) => {
    await initDatabase();
    await requireSection(req, 'storefront');
    const { restaurantId } = req.session;
    if (!restaurantId) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const rows = await db.select({
      name: restaurants.name,
      cuisine_type: restaurants.cuisineType,
      phone: restaurants.phone,
      address: restaurants.address,
      description: restaurants.description,
      seating_capacity: restaurants.seatingCapacity,
    })
    .from(restaurants)
    .where(eq(restaurants.id, restaurantId));
    const baseRow = rows[0];

    if (!baseRow) {
      return NextResponse.json({ error: 'Restaurant not found' }, { status: 404 });
    }

    // The booking-defaults columns aren't in the drizzle schema yet, so read
    // them straight from SQL. They were added in the task #290 migration.
    const { rows: defRows } = await db.execute(sql`
      SELECT default_booking_duration_min, default_booking_buffer_min,
             default_low_stock_threshold
        FROM restaurants WHERE id = ${restaurantId}
    `);
    const defaults = defRows[0] as {
      default_booking_duration_min?: number;
      default_booking_buffer_min?: number;
      default_low_stock_threshold?: number;
    } | undefined;

    return NextResponse.json({
      profile: {
        ...baseRow,
        default_booking_duration_min: Number(defaults?.default_booking_duration_min ?? 90),
        default_booking_buffer_min: Number(defaults?.default_booking_buffer_min ?? 15),
        default_low_stock_threshold: Number(defaults?.default_low_stock_threshold ?? 5),
      },
    });
  })
);

export const PUT = withErrorHandler(
  withAuth(async (req: AuthedRequest) => {
    await initDatabase();
    await requireSection(req, 'storefront', 'update');
    const { restaurantId } = req.session;
    if (!restaurantId) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const body = await req.json().catch(() => ({}));
    const {
      name,
      cuisine_type,
      phone,
      address,
      description,
      seating_capacity,
      default_booking_duration_min,
      default_booking_buffer_min,
      default_low_stock_threshold,
    } = body as {
      name?: string;
      cuisine_type?: string;
      phone?: string;
      address?: string;
      description?: string;
      seating_capacity?: number;
      default_booking_duration_min?: number;
      default_booking_buffer_min?: number;
      default_low_stock_threshold?: number;
    };

    if (name !== undefined && (typeof name !== 'string' || name.trim().length === 0)) {
      return NextResponse.json({ error: 'Restaurant name cannot be empty' }, { status: 400 });
    }

    if (seating_capacity !== undefined && seating_capacity !== null) {
      const cap = Number(seating_capacity);
      if (!Number.isInteger(cap) || cap < 0) {
        return NextResponse.json({ error: 'Seating capacity must be a non-negative integer' }, { status: 400 });
      }
    }

    if (default_booking_duration_min !== undefined && default_booking_duration_min !== null) {
      const d = Number(default_booking_duration_min);
      if (!Number.isInteger(d) || d < 15 || d > 480) {
        return NextResponse.json({ error: 'Default booking duration must be between 15 and 480 minutes' }, { status: 400 });
      }
    }

    if (default_booking_buffer_min !== undefined && default_booking_buffer_min !== null) {
      const b = Number(default_booking_buffer_min);
      if (!Number.isInteger(b) || b < 0 || b > 60) {
        return NextResponse.json({ error: 'Default booking buffer must be between 0 and 60 minutes' }, { status: 400 });
      }
    }

    if (default_low_stock_threshold !== undefined && default_low_stock_threshold !== null) {
      const t = Number(default_low_stock_threshold);
      if (!Number.isInteger(t) || t < 0 || t > 1000) {
        return NextResponse.json({ error: 'Default low-stock threshold must be between 0 and 1000' }, { status: 400 });
      }
    }

    const sets: SQL[] = [];

    if (name !== undefined) sets.push(sql`name = ${name.trim()}`);
    if ('cuisine_type' in body) sets.push(sql`cuisine_type = ${cuisine_type?.trim() || null}`);
    if ('phone' in body) sets.push(sql`phone = ${phone?.trim() || null}`);
    if ('address' in body) sets.push(sql`address = ${address?.trim() || null}`);
    if ('description' in body) sets.push(sql`description = ${description?.trim() || null}`);
    if ('seating_capacity' in body) {
      sets.push(sql`seating_capacity = ${seating_capacity !== undefined && seating_capacity !== null ? Math.floor(Number(seating_capacity)) : null}`);
    }
    if ('default_booking_duration_min' in body && default_booking_duration_min !== null && default_booking_duration_min !== undefined) {
      sets.push(sql`default_booking_duration_min = ${Math.floor(Number(default_booking_duration_min))}`);
    }
    if ('default_booking_buffer_min' in body && default_booking_buffer_min !== null && default_booking_buffer_min !== undefined) {
      sets.push(sql`default_booking_buffer_min = ${Math.floor(Number(default_booking_buffer_min))}`);
    }
    if ('default_low_stock_threshold' in body && default_low_stock_threshold !== null && default_low_stock_threshold !== undefined) {
      sets.push(sql`default_low_stock_threshold = ${Math.floor(Number(default_low_stock_threshold))}`);
    }

    if (sets.length === 0) {
      return NextResponse.json({ error: 'No fields to update' }, { status: 400 });
    }

    sets.push(sql`updated_at = NOW()`);

    // Fetch the current name before overwriting it
    const { rows: beforeRows } = await db.execute(sql`
      SELECT name FROM restaurants WHERE id = ${restaurantId}
    `);
    const oldName = (beforeRows[0] as { name: string } | undefined)?.name ?? '';

    const { rows } = await db.execute(sql`
      UPDATE restaurants SET ${sql.join(sets, sql`, `)}
      WHERE id = ${restaurantId}
      RETURNING name, cuisine_type, phone, address, description, seating_capacity,
                default_booking_duration_min, default_booking_buffer_min,
                default_low_stock_threshold
    `);
    const result = rows[0];

    // If name changed, update branch names that were derived from the old restaurant name.
    // Only branches whose name STARTS WITH the old restaurant name AND have not been
    // manually customised (name_customized = false) are updated.
    if (name !== undefined && name.trim() !== oldName) {
      const newName = name.trim();
      await db.execute(sql`
        UPDATE branches
        SET    name = ${newName} || substring(name from ${oldName.length + 1})
        WHERE  restaurant_id = ${restaurantId}
          AND  name LIKE ${oldName + '%'}
          AND  name_customized = false
      `);
    }

    if (!result) {
      return NextResponse.json({ error: 'Restaurant not found' }, { status: 404 });
    }

    return NextResponse.json({ profile: result });
  })
);
