import { supabase } from "@/lib/supabase"

export type OfflineChat = {
  id: string
  fullName: string
  email: string
  phone: string
  topic: string
  ipAddress: string | null
  userAgent: string | null
  createdAt: string
  updatedAt: string
}

export type OfflineMessage = {
  id: string
  chatId: string
  sender: "visitor" | "admin"
  body: string
  createdAt: string
}

declare global {
  // eslint-disable-next-line no-var
  var __agentOfflineChats: Map<string, OfflineChat> | undefined
  // eslint-disable-next-line no-var
  var __agentOfflineMessages: Map<string, OfflineMessage[]> | undefined
}

function chatsMap() {
  if (!globalThis.__agentOfflineChats) globalThis.__agentOfflineChats = new Map()
  return globalThis.__agentOfflineChats
}

function messagesMap() {
  if (!globalThis.__agentOfflineMessages) globalThis.__agentOfflineMessages = new Map()
  return globalThis.__agentOfflineMessages
}

function newId() {
  return crypto.randomUUID()
}

export async function createOfflineChat(input: {
  fullName: string
  email: string
  phone: string
  topic: string
  ipAddress?: string | null
  userAgent?: string | null
}): Promise<OfflineChat> {
  const now = new Date().toISOString()
  const chat: OfflineChat = {
    id: newId(),
    fullName: input.fullName.trim(),
    email: input.email.trim(),
    phone: input.phone.trim(),
    topic: input.topic.trim(),
    ipAddress: input.ipAddress || null,
    userAgent: input.userAgent || null,
    createdAt: now,
    updatedAt: now,
  }

  chatsMap().set(chat.id, chat)
  messagesMap().set(chat.id, [])

  try {
    await supabase.from("offline_chats").upsert({
      id: chat.id,
      full_name: chat.fullName,
      email: chat.email,
      phone: chat.phone,
      topic: chat.topic,
      ip_address: chat.ipAddress,
      user_agent: chat.userAgent,
      created_at: chat.createdAt,
      updated_at: chat.updatedAt,
    })
  } catch {
    /* table may not exist */
  }

  return chat
}

export async function addOfflineMessage(
  chatId: string,
  sender: "visitor" | "admin",
  body: string
): Promise<OfflineMessage | null> {
  const chat = await getOfflineChat(chatId)
  if (!chat) return null

  const msg: OfflineMessage = {
    id: newId(),
    chatId,
    sender,
    body: body.trim(),
    createdAt: new Date().toISOString(),
  }

  const list = messagesMap().get(chatId) || []
  list.push(msg)
  messagesMap().set(chatId, list)
  chat.updatedAt = msg.createdAt
  chatsMap().set(chatId, chat)

  try {
    const { error: insertError } = await supabase.from("offline_chat_messages").insert({
      id: msg.id,
      chat_id: chatId,
      sender,
      body: msg.body,
      created_at: msg.createdAt,
    })
    if (!insertError) {
      await supabase
        .from("offline_chats")
        .update({ updated_at: msg.createdAt })
        .eq("id", chatId)
    }
  } catch {
    /* table may not exist yet */
  }

  return msg
}

export async function getOfflineChat(chatId: string): Promise<OfflineChat | null> {
  const mem = chatsMap().get(chatId)
  if (mem) return mem

  try {
    const { data } = await supabase
      .from("offline_chats")
      .select("*")
      .eq("id", chatId)
      .maybeSingle()
    if (!data) return null
    const chat: OfflineChat = {
      id: data.id,
      fullName: data.full_name,
      email: data.email,
      phone: data.phone || "",
      topic: data.topic || "",
      ipAddress: data.ip_address,
      userAgent: data.user_agent,
      createdAt: data.created_at,
      updatedAt: data.updated_at,
    }
    chatsMap().set(chat.id, chat)
    return chat
  } catch {
    return null
  }
}

export async function getOfflineMessages(chatId: string): Promise<OfflineMessage[]> {
  const mem = messagesMap().get(chatId) || []
  let fromDb: OfflineMessage[] = []

  try {
    const { data, error } = await supabase
      .from("offline_chat_messages")
      .select("*")
      .eq("chat_id", chatId)
      .order("created_at", { ascending: true })

    if (!error && data?.length) {
      fromDb = data.map((row) => ({
        id: row.id,
        chatId: row.chat_id,
        sender: row.sender as "visitor" | "admin",
        body: row.body,
        createdAt: row.created_at,
      }))
    }
  } catch {
    /* table may not exist */
  }

  const byId = new Map<string, OfflineMessage>()
  for (const m of [...mem, ...fromDb]) {
    byId.set(m.id, m)
  }
  const merged = Array.from(byId.values()).sort(
    (a, b) => +new Date(a.createdAt) - +new Date(b.createdAt)
  )
  messagesMap().set(chatId, merged)
  return merged
}

export async function listOfflineChats(): Promise<
  (OfflineChat & { lastMessage?: string; messageCount: number })[]
> {
  try {
    const { data } = await supabase
      .from("offline_chats")
      .select("*")
      .order("updated_at", { ascending: false })
      .limit(100)
    if (data?.length) {
      for (const row of data) {
        const chat: OfflineChat = {
          id: row.id,
          fullName: row.full_name,
          email: row.email,
          phone: row.phone || "",
          topic: row.topic || "",
          ipAddress: row.ip_address,
          userAgent: row.user_agent,
          createdAt: row.created_at,
          updatedAt: row.updated_at,
        }
        chatsMap().set(chat.id, chat)
      }
    }
  } catch {
    /* ignore */
  }

  const all = Array.from(chatsMap().values()).sort(
    (a, b) => +new Date(b.updatedAt) - +new Date(a.updatedAt)
  )

  return Promise.all(
    all.map(async (c) => {
      const msgs = await getOfflineMessages(c.id)
      return {
        ...c,
        messageCount: msgs.length,
        lastMessage: msgs[msgs.length - 1]?.body,
      }
    })
  )
}
