import { db } from '@server/db/drizzle';
import { sql } from 'drizzle-orm';
import { initDatabase } from '@server/db/init';
import jwt from 'jsonwebtoken';

export interface WidgetSettings {
  id?: string;
  restaurant_id: string;
  primary_color: string;
  welcome_message: string;
  placeholder_text: string;
  position: string;
  auto_open_delay: number;
  bot_name: string;
  show_branding: boolean;
  is_enabled: boolean;
  agent_id?: string | null;
  icon_url?: string | null;
}

export interface WidgetAgent {
  id: string;
  name: string;
  description?: string;
  is_default: boolean;
  is_active: boolean;
  model_id?: string;
  channels: string[];
  branch_id?: string;
}

const _jwtSecretRaw = process.env.JWT_SECRET || process.env.ENCRYPTION_KEY;
if (!_jwtSecretRaw) {
  throw new Error('[RestroAgent] JWT_SECRET or ENCRYPTION_KEY environment variable must be set');
}
const JWT_SECRET: string = _jwtSecretRaw;

export function signWidgetToken(restaurantId: string, conversationId: string): string {
  return jwt.sign({ restaurantId, conversationId, type: 'widget' }, JWT_SECRET, { expiresIn: '7d' });
}

export function verifyWidgetToken(token: string): { restaurantId: string; conversationId: string } | null {
  try {
    const raw = jwt.verify(token, JWT_SECRET);
    if (typeof raw !== 'object' || raw === null) return null;
    const payload = raw as Record<string, unknown>;
    if (payload['type'] !== 'widget' || typeof payload['restaurantId'] !== 'string' || typeof payload['conversationId'] !== 'string') return null;
    return { restaurantId: payload['restaurantId'], conversationId: payload['conversationId'] };
  } catch {
    return null;
  }
}

export async function getWidgetSettings(restaurantId: string): Promise<WidgetSettings | null> {
  await initDatabase();
  /* raw: SELECT * FROM widget_settings WHERE restaurant_id = $1 */
  const { rows } = await db.execute(sql`SELECT * FROM widget_settings WHERE restaurant_id = ${restaurantId}`);
  const row = rows[0] as unknown as WidgetSettings | undefined;
  if (!row) {
    return {
      restaurant_id: restaurantId,
      primary_color: '#f97316',
      welcome_message: 'Hi! How can we help you today?',
      placeholder_text: 'Type your message...',
      position: 'bottom-right',
      auto_open_delay: 0,
      bot_name: 'AI Assistant',
      show_branding: true,
      is_enabled: true,
      agent_id: null,
    };
  }
  return row;
}

export async function upsertWidgetSettings(restaurantId: string, data: Partial<WidgetSettings>): Promise<WidgetSettings> {
  await initDatabase();
  /* raw: INSERT INTO widget_settings (...) VALUES (...) ON CONFLICT (restaurant_id) DO UPDATE SET ... RETURNING * */
  const { rows } = await db.execute(sql`
    INSERT INTO widget_settings (restaurant_id, primary_color, welcome_message, placeholder_text, position, auto_open_delay, bot_name, show_branding, is_enabled, agent_id, icon_url)
    VALUES (${restaurantId},
            ${data.primary_color ?? '#f97316'},
            ${data.welcome_message ?? 'Hi! How can we help you today?'},
            ${data.placeholder_text ?? 'Type your message...'},
            ${data.position ?? 'bottom-right'},
            ${data.auto_open_delay ?? 0},
            ${data.bot_name ?? 'AI Assistant'},
            ${data.show_branding ?? true},
            ${data.is_enabled ?? true},
            ${data.agent_id ?? null},
            ${data.icon_url ?? null})
    ON CONFLICT (restaurant_id) DO UPDATE SET
      primary_color = EXCLUDED.primary_color,
      welcome_message = EXCLUDED.welcome_message,
      placeholder_text = EXCLUDED.placeholder_text,
      position = EXCLUDED.position,
      auto_open_delay = EXCLUDED.auto_open_delay,
      bot_name = EXCLUDED.bot_name,
      show_branding = EXCLUDED.show_branding,
      is_enabled = EXCLUDED.is_enabled,
      agent_id = EXCLUDED.agent_id,
      icon_url = EXCLUDED.icon_url,
      updated_at = NOW()
    RETURNING *
  `);
  return rows[0] as unknown as WidgetSettings;
}

export async function getRestaurantForWidget(restaurantId: string): Promise<{ id: string; name: string; logo_url?: string } | null> {
  await initDatabase();
  /* raw: SELECT id, name, logo_url FROM restaurants WHERE id = $1 AND status = 'active' */
  const { rows } = await db.execute(sql`SELECT id, name, logo_url FROM restaurants WHERE id = ${restaurantId} AND status = 'active'`);
  return (rows[0] as unknown as { id: string; name: string; logo_url?: string }) || null;
}

export async function getChatAgentsForRestaurant(restaurantId: string): Promise<WidgetAgent[]> {
  await initDatabase();
  /* raw: SELECT a.id, a.name, a.description, a.is_default, a.is_active, a.channels, a.branch_id, lm.model_id ... FROM ai_agents a LEFT JOIN llm_models lm ... WHERE ... ORDER BY ... */
  const { rows } = await db.execute(sql`
    SELECT a.id, a.name, a.description, a.is_default, a.is_active, a.channels, a.branch_id,
           lm.model_id as model_id
    FROM ai_agents a
    LEFT JOIN llm_models lm ON lm.id = a.llm_model_id
    WHERE a.restaurant_id = ${restaurantId} AND a.is_active = true AND 'chat' = ANY(a.channels)
    ORDER BY a.is_default DESC, a.name
  `);
  return rows as unknown as WidgetAgent[];
}

export async function createWidgetConversation(
  restaurantId: string,
  customerName: string,
  agentId?: string | null
): Promise<{ id: string }> {
  await initDatabase();
  /* raw: INSERT INTO conversations (...) VALUES (...) RETURNING id */
  const { rows } = await db.execute(sql`
    INSERT INTO conversations (restaurant_id, customer_name, channel, status, messages, topic, unread_count)
    VALUES (${restaurantId}, ${customerName || 'Website Visitor'}, 'chat', 'ai', '[]'::jsonb, 'Chat Widget', 0)
    RETURNING id
  `);
  return rows[0] as unknown as { id: string };
}

export async function appendWidgetMessage(
  conversationId: string,
  restaurantId: string,
  sender: string,
  content: string
): Promise<void> {
  const msg = {
    id: `msg_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`,
    sender,
    content,
    text: content,
    time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
    timestamp: new Date().toISOString(),
  };
  /* raw: UPDATE conversations SET messages = messages || $1::jsonb, unread_count = CASE ... END, updated_at = NOW() WHERE id = $2 AND restaurant_id = $4 */
  await db.execute(sql`
    UPDATE conversations
    SET messages = messages || ${JSON.stringify([msg])}::jsonb,
        unread_count = CASE WHEN ${sender} = 'customer' THEN unread_count + 1 ELSE unread_count END,
        updated_at = NOW()
    WHERE id = ${conversationId} AND restaurant_id = ${restaurantId}
  `);
}

export async function getWidgetConversation(conversationId: string, restaurantId: string) {
  await initDatabase();
  /* raw: SELECT * FROM conversations WHERE id = $1 AND restaurant_id = $2 */
  const { rows } = await db.execute(sql`SELECT * FROM conversations WHERE id = ${conversationId} AND restaurant_id = ${restaurantId}`);
  return rows[0] ?? null;
}

export async function updateWidgetConversationStatus(
  conversationId: string,
  restaurantId: string,
  status: string,
  topic?: string
) {
  /* raw: UPDATE conversations SET status = $1, topic = COALESCE($4, topic), updated_at = NOW() WHERE id = $2 AND restaurant_id = $3 */
  await db.execute(sql`
    UPDATE conversations SET status = ${status}, topic = COALESCE(${topic || null}, topic), updated_at = NOW()
    WHERE id = ${conversationId} AND restaurant_id = ${restaurantId}
  `);
}
