import { NextResponse } from 'next/server';
import { withErrorHandler } from '@server/middleware/withErrorHandler';
import { withAuth, AuthedRequest } from '@server/middleware/withAuth';
import { ForbiddenError, ValidationError } from '@server/errors';
import { db, languages } from '@server/db/drizzle';
import { sql } from 'drizzle-orm';

interface ImportPayload {
  version?: number;
  language?: {
    code?: string;
    name?: string;
    native_name?: string;
    flag_emoji?: string;
    is_rtl?: boolean;
  };
  translations?: Record<string, string>;
}

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

    let body: ImportPayload;
    try {
      body = await req.json() as ImportPayload;
    } catch {
      throw new ValidationError('Invalid JSON body');
    }

    if (!body.translations || typeof body.translations !== 'object' || Array.isArray(body.translations)) {
      throw new ValidationError('Payload must include a "translations" object');
    }

    const nonStringKeys = Object.entries(body.translations)
      .filter(([, v]) => typeof v !== 'string')
      .map(([k]) => k);
    if (nonStringKeys.length > 0) {
      throw new ValidationError(
        `All translation values must be strings. Non-string values found for: ${nonStringKeys.slice(0, 5).join(', ')}${nonStringKeys.length > 5 ? ` … and ${nonStringKeys.length - 5} more` : ''}`
      );
    }

    const meta = body.language ?? {};
    const langName = (meta.name ?? langCode).trim();
    const nativeName = (meta.native_name ?? langName).trim();
    const flagEmoji = (meta.flag_emoji ?? '').trim();
    const isRtl = Boolean(meta.is_rtl ?? false);

    let imported = 0;
    await db.transaction(async (tx) => {
      /*
       * raw:
       * INSERT INTO public.languages (code, name, native_name, flag_emoji, is_rtl, is_active, is_default, display_order)
       * VALUES ($1, $2, $3, $4, $5, true, false, (SELECT COALESCE(MAX(display_order), -1) + 1 FROM public.languages))
       * ON CONFLICT (code) DO UPDATE SET name = EXCLUDED.name, native_name = EXCLUDED.native_name,
       *   flag_emoji = EXCLUDED.flag_emoji, is_rtl = EXCLUDED.is_rtl
       */
      await tx.insert(languages).values({
        code: langCode,
        name: langName,
        nativeName: nativeName,
        flagEmoji: flagEmoji,
        isRtl: isRtl,
        isActive: true,
        isDefault: false,
        displayOrder: sql<number>`(SELECT COALESCE(MAX(display_order), -1) + 1 FROM public.languages)`,
      }).onConflictDoUpdate({
        target: languages.code,
        set: {
          name: sql`excluded.name`,
          nativeName: sql`excluded.native_name`,
          flagEmoji: sql`excluded.flag_emoji`,
          isRtl: sql`excluded.is_rtl`,
        },
      });

      /*
       * raw:
       * INSERT INTO public.translations (lang_code, key_id, value)
       * SELECT $1, tk.id, COALESCE(t_en.value, '')
       * FROM public.translation_keys tk
       * LEFT JOIN public.translations t_en ON t_en.key_id = tk.id AND t_en.lang_code = 'en'
       * ON CONFLICT (lang_code, key_id) DO NOTHING
       */
      await tx.execute(sql`
        INSERT INTO public.translations (lang_code, key_id, value)
        SELECT ${langCode}, tk.id, COALESCE(t_en.value, '')
        FROM public.translation_keys tk
        LEFT JOIN public.translations t_en ON t_en.key_id = tk.id AND t_en.lang_code = 'en'
        ON CONFLICT (lang_code, key_id) DO NOTHING
      `);

      for (const [key, value] of Object.entries(body.translations!)) {
        if (typeof value !== 'string') 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()
         */
        const result = await tx.execute(sql`
          INSERT INTO public.translations (lang_code, key_id, value, updated_at)
          SELECT ${langCode}, tk.id, ${value}, now()
          FROM public.translation_keys tk WHERE tk.key = ${key}
          ON CONFLICT (lang_code, key_id) DO UPDATE SET value = ${value}, updated_at = now()
        `);
        imported += (result as { rowCount?: number }).rowCount ?? 0;
      }
    });

    return NextResponse.json({ ok: true, imported });
  })
);
