import { NextResponse } from 'next/server';
import { withErrorHandler } from '@server/middleware/withErrorHandler';
import { withAuth, requireSection, AuthedRequest } from '@server/middleware/withAuth';
import { db } from '@server/db/drizzle';
import { sql } from 'drizzle-orm';
import { initDatabase } from '@server/db/init';
import { sendAgentMessage } from '@server/integrations/ai/restaurantChatAgent';
import { filterOrderableItems } from '@server/services/menu.service';
import { resolveApiKey } from '@server/services/provider-keys.service';
import { DEFAULT_LLM_MODEL } from '@server/config/ai-defaults';
import { requirePlanFeature } from '@server/utils/features';

interface DraftConfig {
  agentId?: string | null;
  systemPrompt?: string;
  greetingScript?: string;
  closingScript?: string;
  fallbackRules?: Array<{ trigger: string; action: string; priority: string }>;
  modelId?: string | null;
  llmModelId?: string | null;
  branchId?: string | null;
  capabilities?: Record<string, boolean> | null;
  menuCategoryIds?: string[] | null;
  knowledgeBaseIds?: string[] | null;
}

/**
 * In-drawer "Test Agent" endpoint — works for BOTH saved and unsaved
 * agents. Runs the operator's draft config against a caller-supplied
 * chat history. Conversations table is not touched; KB / menu scoping
 * comes entirely from the draft payload (no DB lookup of persisted
 * agent fields, no agent_knowledge_bases join writes).
 */
export const POST = withErrorHandler(
  withAuth(async (req: AuthedRequest) => {
    const { restaurantId } = req.session;
    if (!restaurantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });

    await requireSection(req, 'ai_config');
    await requirePlanFeature(restaurantId, 'chat_agent');

    const body = await req.json() as {
      messages?: Array<{ role: 'user' | 'assistant'; content: string }>;
      draft?: DraftConfig;
    };
    const messages = Array.isArray(body.messages) ? body.messages : [];
    const draft: DraftConfig = body.draft ?? {};
    if (messages.length === 0) {
      return NextResponse.json({ error: 'messages[] is required' }, { status: 400 });
    }

    await initDatabase();

    // If a saved agent id is supplied, confirm it belongs to this restaurant
    // — protects against cross-tenant id spoofing. Unsaved agents skip this.
    if (draft.agentId) {
      const ownership = await db.execute(sql`
        SELECT a.id FROM ai_agents a
         WHERE a.id = ${draft.agentId} AND a.restaurant_id = ${restaurantId} LIMIT 1
      `);
      if (ownership.rows.length === 0) {
        return NextResponse.json({ error: 'Agent not found' }, { status: 404 });
      }
    }

    let resolvedModel = DEFAULT_LLM_MODEL;
    if (draft.modelId) {
      resolvedModel = draft.modelId;
    } else if (draft.llmModelId) {
      const r = await db.execute(sql`SELECT model_id FROM llm_models WHERE id = ${draft.llmModelId} LIMIT 1`);
      const row = r.rows[0] as { model_id?: string } | undefined;
      if (row?.model_id) resolvedModel = row.model_id;
    }

    const branchId = draft.branchId ?? null;
    const allowedCats = Array.isArray(draft.menuCategoryIds) && draft.menuCategoryIds.length
      ? new Set(draft.menuCategoryIds) : null;

    const [menuRes, restRes] = await Promise.all([
      db.execute(sql`
        SELECT mi.id, mi.name, mi.price, mi.description, mi.category_id, mc.name AS category
          FROM menu_items mi LEFT JOIN menu_categories mc ON mc.id = mi.category_id
         WHERE mi.restaurant_id = ${restaurantId} AND mi.is_available = true
         LIMIT 60
      `),
      db.execute(sql`SELECT name FROM restaurants WHERE id = ${restaurantId} LIMIT 1`),
    ]);

    interface MenuItemRow { id: string; name: string; price: number; description: string; category_id: string | null; category: string | null }
    const allItems = (menuRes.rows as unknown as MenuItemRow[])
      .filter(r => !allowedCats || (r.category_id && allowedCats.has(r.category_id)))
      .map(r => ({
        id: r.id, name: r.name, price: r.price, description: r.description,
        category: r.category ?? undefined,
      }));
    const orderable = await filterOrderableItems(allItems, branchId);
    const restaurantName = (restRes.rows[0] as { name: string } | undefined)?.name || 'Test Restaurant';

    const apiKey = await resolveApiKey(restaurantId, 'openai');
    const reply = await sendAgentMessage(
      messages,
      {
        model: resolvedModel,
        systemPrompt: draft.systemPrompt,
        greetingScript: draft.greetingScript,
        closingScript: draft.closingScript,
        fallbackRules: Array.isArray(draft.fallbackRules) ? draft.fallbackRules : [],
      },
      restaurantName,
      { items: orderable },
      restaurantId,
      undefined,
      apiKey ?? undefined,
      branchId ?? undefined,
      'widget',
      undefined,
      {
        agentId: draft.agentId ?? null,
        capabilities: draft.capabilities ?? null,
        menuCategoryIds: Array.isArray(draft.menuCategoryIds) ? draft.menuCategoryIds : null,
        knowledgeBaseIds: Array.isArray(draft.knowledgeBaseIds) ? draft.knowledgeBaseIds : null,
      }
    );

    return NextResponse.json({
      reply: reply.content,
      detectedIntent: reply.detectedIntent,
      shouldEscalate: reply.shouldEscalate,
    });
  })
);
