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

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

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

    const lang = rows[0];
    return NextResponse.json({
      language: {
        ...lang,
        native_name: lang.nativeName,
        flag_emoji: lang.flagEmoji,
        is_rtl: lang.isRtl,
        is_active: lang.isActive,
        is_default: lang.isDefault,
        display_order: lang.displayOrder,
        created_at: lang.createdAt,
        updated_at: lang.updatedAt,
      },
    });
  })
);

export const PATCH = withErrorHandler(
  withAuth(async (req: AuthedRequest, context: { params: Promise<Record<string, string>> }) => {
    if (req.session.role !== 'superadmin' && req.session.role !== 'support') {
      throw new ForbiddenError();
    }
    const { code } = await context.params;
    let body: Partial<{
      name: string;
      native_name: string;
      flag_emoji: string;
      is_rtl: boolean;
      is_active: boolean;
      is_default: boolean;
      display_order: number;
    }>;
    try {
      body = await req.json() as typeof body;
    } catch {
      throw new ValidationError('Request body must be valid JSON');
    }

    const updated = await db.transaction(async (tx) => {
      /*
       * raw: SELECT * FROM public.languages WHERE code = $1
       */
      const existing = await tx.select().from(languages).where(eq(languages.code, code));
      if (existing.length === 0) throw new NotFoundError('Language not found');
      const current = existing[0];

      if (body.is_active === false && current.isDefault) {
        throw new ValidationError('Cannot deactivate the default language. Set another language as default first.');
      }

      if (body.is_default === false && current.isDefault) {
        throw new ValidationError('Cannot unset default directly. Set another language as default instead.');
      }

      if (body.is_default === true) {
        const isActive = body.is_active !== undefined ? body.is_active : current.isActive;
        if (!isActive) {
          throw new ValidationError('Cannot set an inactive language as the default. Activate it first.');
        }
        /*
         * raw: UPDATE public.languages SET is_default = false WHERE is_default = true
         */
        await tx.update(languages).set({ isDefault: false }).where(eq(languages.isDefault, true));
      }

      type LangPatch = {
        name?: string;
        nativeName?: string;
        flagEmoji?: string;
        isRtl?: boolean;
        isActive?: boolean;
        isDefault?: boolean;
        displayOrder?: number;
        updatedAt?: SQL;
      };

      const patch: LangPatch = {};
      if ('name' in body && body.name !== undefined) patch.name = body.name;
      if ('native_name' in body && body.native_name !== undefined) patch.nativeName = body.native_name;
      if ('flag_emoji' in body && body.flag_emoji !== undefined) patch.flagEmoji = body.flag_emoji;
      if ('is_rtl' in body && body.is_rtl !== undefined) patch.isRtl = body.is_rtl;
      if ('is_active' in body && body.is_active !== undefined) patch.isActive = body.is_active;
      if ('is_default' in body && body.is_default !== undefined) patch.isDefault = body.is_default;
      if ('display_order' in body && body.display_order !== undefined) patch.displayOrder = body.display_order;

      if (Object.keys(patch).length === 0) throw new ValidationError('No valid fields to update');

      patch.updatedAt = sql`now()`;

      /*
       * raw: UPDATE public.languages SET ... WHERE code = $n RETURNING *
       */
      const [row] = await tx.update(languages)
        .set(patch)
        .where(eq(languages.code, code))
        .returning();

      return row;
    });

    return NextResponse.json({
      language: {
        ...updated,
        native_name: updated.nativeName,
        flag_emoji: updated.flagEmoji,
        is_rtl: updated.isRtl,
        is_active: updated.isActive,
        is_default: updated.isDefault,
        display_order: updated.displayOrder,
        created_at: updated.createdAt,
        updated_at: updated.updatedAt,
      },
    });
  })
);

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

    /*
     * raw: SELECT is_default FROM public.languages WHERE code = $1
     */
    const rows = await db.select({ is_default: languages.isDefault })
      .from(languages)
      .where(eq(languages.code, code));
    if (rows.length === 0) throw new NotFoundError('Language not found');
    if (rows[0].is_default) {
      throw new ValidationError('Cannot delete the default language. Set another language as default first.');
    }
    if (code === 'en') {
      throw new ValidationError('Cannot delete the English base language.');
    }

    /*
     * raw: DELETE FROM public.languages WHERE code = $1
     */
    await db.delete(languages).where(eq(languages.code, code));
    return NextResponse.json({ ok: true });
  })
);
