import type { FastifyInstance } from 'fastify';
import type { FastifySchema } from 'fastify';
import type pg from 'pg';
import { z } from 'zod';
import type { Authenticate } from '../../../shared/auth.js';
import { requireRole } from '../../../shared/auth.js';
import { parseJson } from '../../../shared/http-input.js';
import { errorSchema } from '../../../shared/swagger.js';

export interface StoreSettingsRoutesDeps {
  pool: pg.Pool;
  authenticate: Authenticate;
}

const updateSettingsSchema = z.object({
  storeName: z.string().min(1).max(120).optional(),
  storeTagline: z.string().max(200).optional(),
  contactEmail: z.string().email().optional(),
  contactPhone: z.string().max(40).optional(),
  contactAddress: z.string().max(400).optional(),
  footerText: z.string().max(400).optional(),
  facebookUrl: z.string().url().optional().or(z.literal('')),
  instagramUrl: z.string().url().optional().or(z.literal('')),
  aiProvider: z.string().max(80).optional(),
  aiBaseUrl: z.string().url().optional().or(z.literal('')),
  aiModel: z.string().max(120).optional(),
  aiApiKey: z.string().max(500).optional(),
  aiSeoTitlePrompt: z.string().max(2000).optional(),
  aiSeoDescriptionPrompt: z.string().max(4000).optional(),
  aiProductDescriptionPrompt: z.string().max(4000).optional(),
  aiCategoryDescriptionPrompt: z.string().max(4000).optional(),
  aiCategorySeoTitlePrompt: z.string().max(2000).optional(),
  aiCategorySeoDescriptionPrompt: z.string().max(4000).optional(),
  smtpHost: z.string().max(255).optional(),
  smtpPort: z.coerce.number().int().min(1).max(65535).optional(),
  smtpSecure: z.boolean().optional(),
  smtpUser: z.string().max(255).optional(),
  smtpPass: z.string().max(500).optional(),
  smtpFrom: z.string().email().optional().or(z.literal('')),
  couriers: z.array(z.string().trim().min(1).max(60)).max(30).optional(),
});

/** Lista de transportistas por defecto hasta que el admin la edite. */
export const DEFAULT_COURIERS = ['Correos', 'SEUR', 'MRW', 'GLS', 'DHL', 'UPS'];

export function parseCouriers(raw: string | undefined | null): string[] {
  if (!raw?.trim()) return [...DEFAULT_COURIERS];
  try {
    const parsed: unknown = JSON.parse(raw);
    if (!Array.isArray(parsed)) return [...DEFAULT_COURIERS];
    const list = parsed
      .filter((item): item is string => typeof item === 'string')
      .map((item) => item.trim())
      .filter((item) => item.length > 0)
      .slice(0, 30);
    return list.length > 0 ? list : [...DEFAULT_COURIERS];
  } catch {
    return [...DEFAULT_COURIERS];
  }
}

const SETTING_KEYS: Record<string, string> = {
  storeName: 'store_name',
  storeTagline: 'store_tagline',
  contactEmail: 'contact_email',
  contactPhone: 'contact_phone',
  contactAddress: 'contact_address',
  footerText: 'footer_text',
  facebookUrl: 'facebook_url',
  instagramUrl: 'instagram_url',
  aiProvider: 'ai_provider',
  aiBaseUrl: 'ai_base_url',
  aiModel: 'ai_model',
  aiApiKey: 'ai_api_key',
  aiSeoTitlePrompt: 'ai_seo_title_prompt',
  aiSeoDescriptionPrompt: 'ai_seo_description_prompt',
  aiProductDescriptionPrompt: 'ai_product_description_prompt',
  aiCategoryDescriptionPrompt: 'ai_category_description_prompt',
  aiCategorySeoTitlePrompt: 'ai_category_seo_title_prompt',
  aiCategorySeoDescriptionPrompt: 'ai_category_seo_description_prompt',
  smtpHost: 'smtp_host',
  smtpPort: 'smtp_port',
  smtpSecure: 'smtp_secure',
  smtpUser: 'smtp_user',
  smtpPass: 'smtp_pass',
  smtpFrom: 'smtp_from',
};

export async function registerStoreSettingsRoutes(
  app: FastifyInstance,
  deps: StoreSettingsRoutesDeps,
): Promise<void> {
  // GET /admin/settings — fetch all settings
  const getSettingsSchema: FastifySchema = {
    tags: ['Admin'],
    summary: 'Get store settings (admin)',
    response: { 401: errorSchema, 403: errorSchema },
  };
  app.get('/admin/settings', { schema: getSettingsSchema }, async (request, reply) => {
    const user = await deps.authenticate(request);
    requireRole(user, 'admin');
    const result = await deps.pool.query<{ key: string; value: string }>(
      `SELECT key, value FROM store_settings`,
    );
    const map: Record<string, string> = {};
    for (const row of result.rows) {
      map[row.key] = row.value;
    }
    return reply.send({
      storeName: map['store_name'] ?? '',
      storeTagline: map['store_tagline'] ?? '',
      contactEmail: map['contact_email'] ?? '',
      contactPhone: map['contact_phone'] ?? '',
      contactAddress: map['contact_address'] ?? '',
      footerText: map['footer_text'] ?? '',
      facebookUrl: map['facebook_url'] ?? '',
      instagramUrl: map['instagram_url'] ?? '',
      aiProvider: map['ai_provider'] ?? '',
      aiBaseUrl: map['ai_base_url'] ?? '',
      aiModel: map['ai_model'] ?? '',
      aiApiKey: '',
      aiApiKeyConfigured: Boolean(map['ai_api_key']),
      aiSeoTitlePrompt: map['ai_seo_title_prompt'] ?? 'Genera un título SEO breve y atractivo para este producto: {{name}}. Devuelve solo el título.',
      aiSeoDescriptionPrompt: map['ai_seo_description_prompt'] ?? 'Genera una meta descripción SEO en español, clara y persuasiva, para este producto: {{name}}. Devuelve solo la descripción.',
      aiProductDescriptionPrompt: map['ai_product_description_prompt'] ?? 'Escribe una descripción comercial clara y útil en español para este producto: {{name}}. Incluye sus beneficios y características usando solo la información disponible. Devuelve solo la descripción.',
      aiCategoryDescriptionPrompt: map['ai_category_description_prompt'] ?? 'Escribe una descripción breve y atractiva en español para esta categoría de una tienda de productos naturales y ecológicos: {{name}}. Devuelve solo la descripción, sin formato.',
      aiCategorySeoTitlePrompt: map['ai_category_seo_title_prompt'] ?? 'Genera un título SEO breve y atractivo para esta categoría: {{name}}. Devuelve solo el título.',
      aiCategorySeoDescriptionPrompt: map['ai_category_seo_description_prompt'] ?? 'Genera una meta descripción SEO en español, clara y persuasiva, para esta categoría: {{name}}. Devuelve solo la descripción.',
      smtpHost: map['smtp_host'] ?? process.env.SMTP_HOST ?? '',
      smtpPort: map['smtp_port'] ?? process.env.SMTP_PORT ?? '465',
      smtpSecure: (map['smtp_secure'] ?? process.env.SMTP_SECURE ?? 'true') !== 'false',
      smtpUser: map['smtp_user'] ?? process.env.SMTP_USER ?? '',
      smtpPass: '',
      smtpPassConfigured: Boolean(map['smtp_pass'] || process.env.SMTP_PASS),
      smtpFrom: map['smtp_from'] ?? process.env.SMTP_FROM ?? '',
      couriers: parseCouriers(map['shipping_couriers']),
    });
  });

  // PATCH /admin/settings — update one or more settings
  const patchSettingsSchema: FastifySchema = {
    tags: ['Admin'],
    summary: 'Update store settings (admin)',
    body: { type: 'object' },
    response: { 401: errorSchema, 403: errorSchema },
  };
  app.patch('/admin/settings', { schema: patchSettingsSchema }, async (request, reply) => {
    const user = await deps.authenticate(request);
    requireRole(user, 'admin');
    const input = parseJson(updateSettingsSchema, request.body);
    const updates: string[] = [];
    const values: unknown[] = [];
    const identityUser = await deps.pool.query<{ id: string }>(
      `SELECT id FROM identity_users WHERE id = $1`,
      [user.id],
    );
    // Backoffice users are a separate table. Keep the audit FK valid when the
    // authenticated backoffice id has no corresponding identity_users row.
    const updatedBy = identityUser.rowCount ? user.id : null;
    let i = 1;
    for (const [field, dbKey] of Object.entries(SETTING_KEYS)) {
      const val = input[field as keyof typeof input];
      if (val !== undefined) {
        updates.push(`key = CASE WHEN key = $${i} THEN $${i + 1} ELSE key END`);
        values.push(dbKey, val);
        i += 2;
      }
    }
    if (updates.length > 0) {
      // Use INSERT ... ON CONFLICT for each key
      for (const [field, dbKey] of Object.entries(SETTING_KEYS)) {
        const val = input[field as keyof typeof input];
        if (val !== undefined) {
          await deps.pool.query(
            `INSERT INTO store_settings (key, value, updated_by) VALUES ($1, $2, $3)
             ON CONFLICT (key) DO UPDATE SET value = $2, updated_at = NOW(), updated_by = $3`,
            [dbKey, val, updatedBy],
          );
        }
      }
    }
    if (input.couriers !== undefined) {
      await deps.pool.query(
        `INSERT INTO store_settings (key, value, updated_by) VALUES ('shipping_couriers', $1, $2)
         ON CONFLICT (key) DO UPDATE SET value = $1, updated_at = NOW(), updated_by = $2`,
        [JSON.stringify(input.couriers), updatedBy],
      );
    }
    // Return updated settings
    const result = await deps.pool.query<{ key: string; value: string }>(
      `SELECT key, value FROM store_settings`,
    );
    const map: Record<string, string> = {};
    for (const row of result.rows) {
      map[row.key] = row.value;
    }
    return reply.send({
      storeName: map['store_name'] ?? '',
      storeTagline: map['store_tagline'] ?? '',
      contactEmail: map['contact_email'] ?? '',
      contactPhone: map['contact_phone'] ?? '',
      contactAddress: map['contact_address'] ?? '',
      footerText: map['footer_text'] ?? '',
      facebookUrl: map['facebook_url'] ?? '',
      instagramUrl: map['instagram_url'] ?? '',
      aiProvider: map['ai_provider'] ?? '',
      aiBaseUrl: map['ai_base_url'] ?? '',
      aiModel: map['ai_model'] ?? '',
      aiApiKey: '',
      aiApiKeyConfigured: Boolean(map['ai_api_key']),
      aiSeoTitlePrompt: map['ai_seo_title_prompt'] ?? 'Genera un título SEO breve y atractivo para este producto: {{name}}. Devuelve solo el título.',
      aiSeoDescriptionPrompt: map['ai_seo_description_prompt'] ?? 'Genera una meta descripción SEO en español, clara y persuasiva, para este producto: {{name}}. Incluye sus beneficios y características usando solo la información disponible. Devuelve solo la descripción.',
      aiProductDescriptionPrompt: map['ai_product_description_prompt'] ?? 'Escribe una descripción comercial clara y útil en español para este producto: {{name}}. Incluye sus beneficios y características usando solo la información disponible. Devuelve solo la descripción.',
      aiCategoryDescriptionPrompt: map['ai_category_description_prompt'] ?? 'Escribe una descripción breve y atractiva en español para esta categoría de una tienda de productos naturales y ecológicos: {{name}}. Devuelve solo la descripción, sin formato.',
      aiCategorySeoTitlePrompt: map['ai_category_seo_title_prompt'] ?? 'Genera un título SEO breve y atractivo para esta categoría: {{name}}. Devuelve solo el título.',
      aiCategorySeoDescriptionPrompt: map['ai_category_seo_description_prompt'] ?? 'Genera una meta descripción SEO en español, clara y persuasiva, para esta categoría: {{name}}. Devuelve solo la descripción.',
      smtpHost: map['smtp_host'] ?? process.env.SMTP_HOST ?? '',
      smtpPort: map['smtp_port'] ?? process.env.SMTP_PORT ?? '465',
      smtpSecure: (map['smtp_secure'] ?? process.env.SMTP_SECURE ?? 'true') !== 'false',
      smtpUser: map['smtp_user'] ?? process.env.SMTP_USER ?? '',
      smtpPass: '',
      smtpPassConfigured: Boolean(map['smtp_pass'] || process.env.SMTP_PASS),
      smtpFrom: map['smtp_from'] ?? process.env.SMTP_FROM ?? '',
      couriers: parseCouriers(map['shipping_couriers']),
    });
  });
}
