import { NextResponse } from 'next/server';
import { withErrorHandler } from '@server/middleware/withErrorHandler';
import { withAuth, AuthedRequest } from '@server/middleware/withAuth';
import { ForbiddenError, NotFoundError } from '@server/errors';
import { db, languages, translations, translationKeys } from '@server/db/drizzle';
import { eq, sql, asc } from 'drizzle-orm';
import OpenAI from 'openai';
import { getPlatformSettings } from '@server/services/admin.service';

import { childLogger } from '@server/logger';
const log = childLogger('route.admin.translations.langCode.ai_translate');

const LANGUAGE_NAMES: Record<string, string> = {
  hi: 'Hindi',
  de: 'German',
  fr: 'French',
  ru: 'Russian',
  ar: 'Arabic',
  es: 'Spanish',
  zh: 'Chinese (Simplified)',
  ja: 'Japanese',
  pt: 'Portuguese',
  it: 'Italian',
  nl: 'Dutch',
  tr: 'Turkish',
  ko: 'Korean',
};

const BATCH_SIZE = 50;

export const POST = withErrorHandler(
  withAuth(async (req: AuthedRequest, context: { params: Promise<Record<string, string>> }) => {
    if (req.session.role !== 'superadmin') {
      throw new ForbiddenError();
    }

    const { langCode } = await context.params;

    let apiKey = process.env.OPENAI_API_KEY;
    if (!apiKey) {
      const platformSettings = await getPlatformSettings();
      const dbKey = platformSettings.openai_api_key as string | undefined;
      if (dbKey && dbKey.trim().length > 0) {
        apiKey = dbKey.trim();
      }
    }
    if (!apiKey) {
      return NextResponse.json({ error: 'OPENAI_API_KEY is not configured' }, { status: 500 });
    }

    /*
     * raw: SELECT * FROM public.languages WHERE code = $1
     */
    const langRows = await db.select().from(languages).where(eq(languages.code, langCode));
    if (langRows.length === 0) throw new NotFoundError('Language not found');
    const lang = langRows[0];

    if (langCode === 'en') {
      return NextResponse.json({ ok: true, translated: 0, message: 'English is the source language' });
    }

    /*
     * raw:
     * SELECT tk.key, tk.default_value FROM public.translation_keys tk
     * LEFT JOIN public.translations t ON t.key_id = tk.id AND t.lang_code = $1
     * WHERE COALESCE(t.value, '') = ''
     * ORDER BY tk.category ASC, tk.key ASC
     */
    const untranslated = await db
      .select({ key: translationKeys.key, default_value: translationKeys.defaultValue })
      .from(translationKeys)
      .leftJoin(translations, sql`${translations.keyId} = ${translationKeys.id} AND ${translations.langCode} = ${langCode}`)
      .where(sql`COALESCE(${translations.value}, '') = ''`)
      .orderBy(asc(translationKeys.category), asc(translationKeys.key));

    if (untranslated.length === 0) {
      return NextResponse.json({ ok: true, translated: 0, message: 'All keys already translated' });
    }

    const targetLanguage = LANGUAGE_NAMES[langCode] ?? lang.name;
    const openai = new OpenAI({ apiKey });
    let totalTranslated = 0;

    for (let i = 0; i < untranslated.length; i += BATCH_SIZE) {
      const batch = untranslated.slice(i, i + BATCH_SIZE);
      const inputMap: Record<string, string> = {};
      for (const row of batch) {
        inputMap[row.key] = row.default_value;
      }

      const systemPrompt = `You are a professional UI translator for a restaurant management SaaS platform called RestroAgent.
Translate the given JSON object from English to ${targetLanguage}.
Rules:
- Preserve ALL double-brace placeholder tokens exactly as-is (e.g. {{count}}, {{name}}, {{date}}, {{lang}}). These are template variables used at runtime and MUST remain unchanged with the double braces.
- Do NOT convert {{var}} to {var} or any other format — always use exactly double braces.
- Keep brand names (RestroAgent, WhatsApp, DoorDash, etc.) untranslated.
- Use formal, professional register suitable for a business dashboard.
- Return only a valid JSON object with the same keys mapped to their translated values.
- Do NOT add commentary, code fences, or any text outside the JSON.`;

      const userPrompt = JSON.stringify(inputMap, null, 2);

      let resultMap: Record<string, string> = {};
      try {
        const completion = await openai.chat.completions.create({
          model: 'gpt-4o-mini',
          messages: [
            { role: 'system', content: systemPrompt },
            { role: 'user', content: userPrompt },
          ],
          temperature: 0.2,
          response_format: { type: 'json_object' },
        });

        const content = completion.choices[0]?.message?.content ?? '{}';
        resultMap = JSON.parse(content) as Record<string, string>;
      } catch (err) {
        const apiErr = err as { status?: number; code?: string; message?: string };
        const status = apiErr.status;
        const code = apiErr.code ?? 'unknown';
        const message = apiErr.message ?? String(err);
        log.error({ batch: i, status: status ?? null, code, message }, 'ai-translate batch failed');
        if (status === 401 || code === 'invalid_api_key') {
          log.error({ batch: i }, 'ai-translate: invalid API key — aborting all remaining batches');
          break;
        }
        if (code === 'insufficient_quota') {
          log.error({ batch: i }, 'ai-translate: OpenAI quota exceeded — aborting all remaining batches');
          break;
        }
        continue;
      }

      try {
        await db.transaction(async (tx) => {
          for (const [key, value] of Object.entries(resultMap)) {
            if (typeof value !== 'string' || !value.trim()) continue;
            /*
             * raw:
             * INSERT INTO public.translations (lang_code, key_id, value, updated_at)
             * SELECT $1, tk.id, $2, now() FROM public.translation_keys tk WHERE tk.key = $3
             * ON CONFLICT (lang_code, key_id) DO UPDATE SET value = $2, updated_at = now()
             */
            await tx.execute(sql`
              INSERT INTO public.translations (lang_code, key_id, value, updated_at)
              SELECT ${langCode}, tk.id, ${value.trim()}, now()
              FROM public.translation_keys tk WHERE tk.key = ${key}
              ON CONFLICT (lang_code, key_id) DO UPDATE SET value = ${value.trim()}, updated_at = now()
            `);
            totalTranslated++;
          }
        });
      } catch (err) {
        log.error({ err, batch: i }, 'ai-translate DB write batch failed');
      }
    }

    return NextResponse.json({ ok: true, translated: totalTranslated, total: untranslated.length });
  })
);
