import { useCallback, useEffect, useRef, useState } from "react"
import { invoke } from "@tauri-apps/api/core"
import { listen } from "@tauri-apps/api/event"
import { Store } from "@tauri-apps/plugin-store"
import { appLocalDataDir, join } from "@tauri-apps/api/path"
import { open } from "@tauri-apps/plugin-dialog"
import { Send, X, Loader2, MessageCircle, Paperclip, FileText, Image as ImageIcon, File, User, ChevronUp, Minimize2 } from "lucide-react"
import type { ChatMessage, ChatMessagesResponse, SendMessageResponse } from "./types"

const STORE_FILENAME = "machine-agent.json"
const MAX_MESSAGES_IN_MEMORY = 200 // Limite de mensagens para evitar memory leak

// Tipos de arquivo permitidos
const ALLOWED_EXTENSIONS = [
  "jpg", "jpeg", "png", "gif", "webp",
  "pdf", "txt", "doc", "docx", "xls", "xlsx",
]

interface UploadedAttachment {
  storageId: string
  name: string
  size?: number
  type?: string
}

function getFileIcon(fileName: string) {
  const ext = fileName.toLowerCase().split(".").pop() ?? ""
  if (["jpg", "jpeg", "png", "gif", "webp"].includes(ext)) {
    return <ImageIcon className="size-4" />
  }
  if (["pdf", "doc", "docx", "txt"].includes(ext)) {
    return <FileText className="size-4" />
  }
  return <File className="size-4" />
}

interface ChatWidgetProps {
  ticketId: string
}

export function ChatWidget({ ticketId }: ChatWidgetProps) {
  const [messages, setMessages] = useState<ChatMessage[]>([])
  const [inputValue, setInputValue] = useState("")
  const [isLoading, setIsLoading] = useState(true)
  const [isSending, setIsSending] = useState(false)
  const [isUploading, setIsUploading] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [ticketInfo, setTicketInfo] = useState<{ ref: number; subject: string; agentName: string } | null>(null)
  const [hasSession, setHasSession] = useState(false)
  const [pendingAttachments, setPendingAttachments] = useState<UploadedAttachment[]>([])
  const [isMinimized, setIsMinimized] = useState(false)
  const [unreadCount, setUnreadCount] = useState(0)

  const messagesEndRef = useRef<HTMLDivElement>(null)
  const lastFetchRef = useRef<number>(0)
  const pollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
  const hadSessionRef = useRef<boolean>(false)

  // Scroll para o final quando novas mensagens chegam
  const scrollToBottom = useCallback(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
  }, [])

  useEffect(() => {
    scrollToBottom()
  }, [messages, scrollToBottom])

  // Auto-minimizar quando a sessão termina (hasSession muda de true para false)
  useEffect(() => {
    if (hadSessionRef.current && !hasSession) {
      setIsMinimized(true)
      // Redimensionar janela para modo minimizado
      invoke("set_chat_minimized", { ticketId, minimized: true }).catch(err => {
        console.error("Erro ao minimizar janela automaticamente:", err)
      })
    }
    hadSessionRef.current = hasSession
  }, [hasSession, ticketId])

  // Carregar configuracao do store
  const loadConfig = useCallback(async () => {
    try {
      const appData = await appLocalDataDir()
      const storePath = await join(appData, STORE_FILENAME)
      const store = await Store.load(storePath)
      const token = await store.get<string>("token")
      const config = await store.get<{ apiBaseUrl: string }>("config")

      if (!token || !config?.apiBaseUrl) {
        setError("Máquina não registrada")
        setIsLoading(false)
        return null
      }

      return { token, baseUrl: config.apiBaseUrl }
    } catch (err) {
      setError("Erro ao carregar configuracao")
      setIsLoading(false)
      return null
    }
  }, [])

  // Buscar mensagens
  const fetchMessages = useCallback(async (baseUrl: string, token: string, since?: number) => {
    try {
      const response = await invoke<ChatMessagesResponse>("fetch_chat_messages", {
        baseUrl,
        token,
        ticketId,
        since: since ?? null,
      })

      setHasSession(response.hasSession)

      if (response.messages.length > 0) {
        if (since) {
          // Adicionar apenas novas mensagens (com limite para evitar memory leak)
          setMessages(prev => {
            const existingIds = new Set(prev.map(m => m.id))
            const newMsgs = response.messages.filter(m => !existingIds.has(m.id))
            const combined = [...prev, ...newMsgs]
            // Manter apenas as últimas MAX_MESSAGES_IN_MEMORY mensagens
            return combined.slice(-MAX_MESSAGES_IN_MEMORY)
          })
        } else {
          // Primeira carga (já limitada)
          setMessages(response.messages.slice(-MAX_MESSAGES_IN_MEMORY))
        }
        lastFetchRef.current = Math.max(...response.messages.map(m => m.createdAt))
      }

      return response
    } catch (err) {
      console.error("Erro ao buscar mensagens:", err)
      return null
    }
  }, [ticketId])

  // Buscar info da sessao
  const fetchSessionInfo = useCallback(async (baseUrl: string, token: string) => {
    try {
      const sessions = await invoke<Array<{
        ticketId: string
        ticketRef: number
        ticketSubject: string
        agentName: string
      }>>("fetch_chat_sessions", { baseUrl, token })

      const session = sessions.find(s => s.ticketId === ticketId)
      if (session) {
        setTicketInfo({
          ref: session.ticketRef,
          subject: session.ticketSubject,
          agentName: session.agentName,
        })
      }
    } catch (err) {
      console.error("Erro ao buscar sessao:", err)
    }
  }, [ticketId])

  // Inicializacao
  useEffect(() => {
    let mounted = true

    const init = async () => {
      const config = await loadConfig()
      if (!config || !mounted) return

      const { baseUrl, token } = config

      // Buscar sessao e mensagens iniciais
      await Promise.all([
        fetchSessionInfo(baseUrl, token),
        fetchMessages(baseUrl, token),
      ])

      if (!mounted) return
      setIsLoading(false)

      // Iniciar polling (2 segundos para maior responsividade)
      pollIntervalRef.current = setInterval(async () => {
        await fetchMessages(baseUrl, token, lastFetchRef.current)
      }, 2000)
    }

    init()

    // Listener para eventos de nova mensagem do Tauri
    const unlistenNewMessage = listen<{ ticketId: string; message: ChatMessage }>(
      "raven://chat/new-message",
      (event) => {
        if (event.payload.ticketId === ticketId) {
          setMessages(prev => {
            if (prev.some(m => m.id === event.payload.message.id)) {
              return prev
            }
            const combined = [...prev, event.payload.message]
            // Manter apenas as últimas MAX_MESSAGES_IN_MEMORY mensagens
            return combined.slice(-MAX_MESSAGES_IN_MEMORY)
          })
        }
      }
    )

    // Listener para atualização de mensagens não lidas
    const unlistenUnread = listen<{ totalUnread: number; sessions: Array<{ ticketId: string; unreadCount: number }> }>(
      "raven://chat/unread-update",
      (event) => {
        // Encontrar o unread count para este ticket
        const session = event.payload.sessions?.find(s => s.ticketId === ticketId)
        if (session) {
          setUnreadCount(session.unreadCount ?? 0)
        }
      }
    )

    return () => {
      mounted = false
      if (pollIntervalRef.current) {
        clearInterval(pollIntervalRef.current)
      }
      unlistenNewMessage.then(unlisten => unlisten())
      unlistenUnread.then(unlisten => unlisten())
    }
  }, [ticketId, loadConfig, fetchMessages, fetchSessionInfo])

  // Selecionar arquivo para anexar
  const handleAttach = async () => {
    if (isUploading || isSending) return

    try {
      const selected = await open({
        multiple: false,
        filters: [{
          name: "Arquivos permitidos",
          extensions: ALLOWED_EXTENSIONS,
        }],
      })

      if (!selected) return

      // O retorno pode ser string (path único) ou objeto com path
      const filePath = typeof selected === "string" ? selected : (selected as { path: string }).path

      setIsUploading(true)

      const config = await loadConfig()
      if (!config) {
        setIsUploading(false)
        return
      }

      const attachment = await invoke<UploadedAttachment>("upload_chat_file", {
        baseUrl: config.baseUrl,
        token: config.token,
        filePath,
      })

      setPendingAttachments(prev => [...prev, attachment])
    } catch (err) {
      console.error("Erro ao anexar arquivo:", err)
      alert(typeof err === "string" ? err : "Erro ao anexar arquivo")
    } finally {
      setIsUploading(false)
    }
  }

  // Remover anexo pendente
  const handleRemoveAttachment = (storageId: string) => {
    setPendingAttachments(prev => prev.filter(a => a.storageId !== storageId))
  }

  // Enviar mensagem
  const handleSend = async () => {
    if ((!inputValue.trim() && pendingAttachments.length === 0) || isSending) return

    const messageText = inputValue.trim()
    const attachmentsToSend = [...pendingAttachments]
    setInputValue("")
    setPendingAttachments([])
    setIsSending(true)

    try {
      const config = await loadConfig()
      if (!config) {
        setIsSending(false)
        setInputValue(messageText)
        setPendingAttachments(attachmentsToSend)
        return
      }

      const response = await invoke<SendMessageResponse>("send_chat_message", {
        baseUrl: config.baseUrl,
        token: config.token,
        ticketId,
        body: messageText || (attachmentsToSend.length > 0 ? "[Anexo]" : ""),
        attachments: attachmentsToSend.length > 0 ? attachmentsToSend : null,
      })

      // Adicionar mensagem localmente
      setMessages(prev => [...prev, {
        id: response.messageId,
        body: messageText || (attachmentsToSend.length > 0 ? "[Anexo]" : ""),
        authorName: "Voce",
        isFromMachine: true,
        createdAt: response.createdAt,
        attachments: attachmentsToSend.map(a => ({
          storageId: a.storageId,
          name: a.name,
          size: a.size,
          type: a.type,
        })),
      }])

      lastFetchRef.current = response.createdAt
    } catch (err) {
      console.error("Erro ao enviar mensagem:", err)
      // Restaurar input e anexos em caso de erro
      setInputValue(messageText)
      setPendingAttachments(attachmentsToSend)
    } finally {
      setIsSending(false)
    }
  }

  const handleMinimize = async () => {
    setIsMinimized(true)
    try {
      await invoke("set_chat_minimized", { ticketId, minimized: true })
    } catch (err) {
      console.error("Erro ao minimizar janela:", err)
    }
  }

  const handleExpand = async () => {
    setIsMinimized(false)
    try {
      await invoke("set_chat_minimized", { ticketId, minimized: false })
    } catch (err) {
      console.error("Erro ao expandir janela:", err)
    }
  }

  const handleClose = () => {
    invoke("close_chat_window", { ticketId })
  }

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === "Enter" && !e.shiftKey) {
      e.preventDefault()
      handleSend()
    }
  }

  if (isLoading) {
    return (
      <div className="flex h-screen flex-col items-center justify-center bg-white">
        <Loader2 className="size-8 animate-spin text-slate-400" />
        <p className="mt-2 text-sm text-slate-500">Carregando chat...</p>
      </div>
    )
  }

  if (error) {
    return (
      <div className="flex h-screen flex-col items-center justify-center bg-white p-4">
        <p className="text-sm text-red-600">{error}</p>
      </div>
    )
  }

  // Quando não há sessão, mostrar versão minimizada com indicador de offline
  if (!hasSession) {
    return (
      <div className="flex h-full w-full items-end justify-end bg-transparent">
        <div className="flex items-center gap-2 rounded-full bg-slate-200 px-4 py-2 text-slate-600 shadow-lg">
          <MessageCircle className="size-4" />
          <span className="text-sm font-medium">
            {ticketInfo ? `Chat #${ticketInfo.ref}` : "Chat"}
          </span>
          <span className="size-2 rounded-full bg-slate-400" />
          <span className="text-xs text-slate-500">Offline</span>
        </div>
      </div>
    )
  }

  // Versão minimizada (chip compacto igual web)
  if (isMinimized) {
    return (
      <div className="flex h-full w-full items-end justify-end bg-transparent">
        <button
          onClick={handleExpand}
          className="relative flex items-center gap-2 rounded-full bg-black px-4 py-2 text-white shadow-lg hover:bg-black/90"
        >
          <MessageCircle className="size-4" />
          <span className="text-sm font-medium">
            Chat #{ticketInfo?.ref}
          </span>
          <span className="size-2 rounded-full bg-emerald-400" />
          <ChevronUp className="size-4" />
          {/* Badge de mensagens não lidas */}
          {unreadCount > 0 && (
            <span className="absolute -right-1 -top-1 flex size-5 items-center justify-center rounded-full bg-red-500 text-xs font-bold">
              {unreadCount > 9 ? "9+" : unreadCount}
            </span>
          )}
        </button>
      </div>
    )
  }

  return (
    <div className="flex h-screen flex-col overflow-hidden rounded-2xl bg-white shadow-xl">
      {/* Header - arrastavel */}
      <div
        data-tauri-drag-region
        className="flex items-center justify-between border-b border-slate-200 bg-slate-50 px-4 py-3 rounded-t-2xl"
      >
        <div className="flex items-center gap-3">
          <div className="flex size-10 items-center justify-center rounded-full bg-black text-white">
            <MessageCircle className="size-5" />
          </div>
          <div>
            <div className="flex items-center gap-2">
              <p className="text-sm font-semibold text-slate-900">Chat</p>
              <span className="flex items-center gap-1.5 text-xs text-emerald-600">
                <span className="size-2 rounded-full bg-emerald-500 animate-pulse" />
                Online
              </span>
            </div>
            {ticketInfo && (
              <p className="text-xs text-slate-500">
                #{ticketInfo.ref} - {ticketInfo.agentName ?? "Suporte"}
              </p>
            )}
          </div>
        </div>
        <div className="flex items-center gap-1">
          <button
            onClick={handleMinimize}
            className="rounded-md p-1.5 text-slate-500 hover:bg-slate-100"
            title="Minimizar"
          >
            <Minimize2 className="size-4" />
          </button>
          <button
            onClick={handleClose}
            className="rounded-md p-1.5 text-slate-500 hover:bg-slate-100"
            title="Fechar"
          >
            <X className="size-4" />
          </button>
        </div>
      </div>

      {/* Mensagens */}
      <div className="flex-1 overflow-y-auto p-4">
        {messages.length === 0 ? (
          <div className="flex h-full flex-col items-center justify-center text-center">
            <p className="text-sm text-slate-400">
              Nenhuma mensagem ainda
            </p>
            <p className="mt-1 text-xs text-slate-400">
              O agente iniciará a conversa em breve
            </p>
          </div>
        ) : (
          <div className="space-y-4">
            {messages.map((msg) => {
              // No desktop: isFromMachine=true significa mensagem do cliente (maquina)
              // Layout igual à web: cliente à esquerda, agente à direita
              const isAgent = !msg.isFromMachine
              return (
                <div
                  key={msg.id}
                  className={`flex gap-2 ${isAgent ? "flex-row-reverse" : "flex-row"}`}
                >
                  {/* Avatar */}
                  <div
                    className={`flex size-7 shrink-0 items-center justify-center rounded-full ${
                      isAgent ? "bg-black text-white" : "bg-slate-200 text-slate-600"
                    }`}
                  >
                    {isAgent ? <MessageCircle className="size-3.5" /> : <User className="size-3.5" />}
                  </div>

                  {/* Bubble */}
                  <div
                    className={`max-w-[75%] rounded-2xl px-4 py-2 ${
                      isAgent
                        ? "rounded-br-md bg-black text-white"
                        : "rounded-bl-md border border-slate-100 bg-white text-slate-900 shadow-sm"
                    }`}
                  >
                    {!isAgent && (
                      <p className="mb-1 text-xs font-medium text-slate-500">
                        {msg.authorName}
                      </p>
                    )}
                    <p className="whitespace-pre-wrap text-sm">{msg.body}</p>
                    {/* Anexos */}
                    {msg.attachments && msg.attachments.length > 0 && (
                      <div className="mt-2 space-y-1">
                        {msg.attachments.map((att) => (
                          <div
                            key={att.storageId}
                            className={`flex items-center gap-2 rounded-lg p-2 text-xs ${
                              isAgent ? "bg-white/10" : "bg-slate-100"
                            }`}
                          >
                            {getFileIcon(att.name)}
                            <span className="truncate">{att.name}</span>
                            {att.size && (
                              <span className="text-xs opacity-60">
                                ({Math.round(att.size / 1024)}KB)
                              </span>
                            )}
                          </div>
                        ))}
                      </div>
                    )}
                    <p
                      className={`mt-1 text-right text-xs ${
                        isAgent ? "text-white/60" : "text-slate-400"
                      }`}
                    >
                      {formatTime(msg.createdAt)}
                    </p>
                  </div>
                </div>
              )
            })}
            <div ref={messagesEndRef} />
          </div>
        )}
      </div>

      {/* Input */}
      <div className="border-t border-slate-200 p-3">
        {/* Anexos pendentes */}
        {pendingAttachments.length > 0 && (
          <div className="mb-2 flex flex-wrap gap-2">
            {pendingAttachments.map((att) => (
              <div
                key={att.storageId}
                className="flex items-center gap-1 rounded-lg bg-slate-100 px-2 py-1 text-xs"
              >
                {getFileIcon(att.name)}
                <span className="max-w-[100px] truncate">{att.name}</span>
                <button
                  onClick={() => handleRemoveAttachment(att.storageId)}
                  className="ml-1 rounded p-0.5 text-slate-400 hover:bg-slate-200 hover:text-slate-600"
                >
                  <X className="size-3" />
                </button>
              </div>
            ))}
          </div>
        )}
        <div className="flex items-end gap-2">
          <textarea
            value={inputValue}
            onChange={(e) => setInputValue(e.target.value)}
            onKeyDown={handleKeyDown}
            placeholder="Digite sua mensagem..."
            className="max-h-24 min-h-[36px] flex-1 resize-none rounded-lg border border-slate-200 px-3 py-2 text-sm focus:border-slate-400 focus:outline-none focus:ring-1 focus:ring-slate-400"
            rows={1}
          />
          <button
            onClick={handleAttach}
            disabled={isUploading || isSending}
            className="flex size-9 items-center justify-center rounded-lg text-slate-500 transition hover:bg-slate-100 hover:text-slate-700 disabled:opacity-50"
            title="Anexar arquivo"
          >
            {isUploading ? (
              <Loader2 className="size-4 animate-spin" />
            ) : (
              <Paperclip className="size-4" />
            )}
          </button>
          <button
            onClick={handleSend}
            disabled={(!inputValue.trim() && pendingAttachments.length === 0) || isSending}
            className="flex size-9 items-center justify-center rounded-lg bg-black text-white transition hover:bg-black/90 disabled:opacity-50"
          >
            {isSending ? (
              <Loader2 className="size-4 animate-spin" />
            ) : (
              <Send className="size-4" />
            )}
          </button>
        </div>
      </div>
    </div>
  )
}

function formatTime(timestamp: number): string {
  const date = new Date(timestamp)
  return date.toLocaleTimeString("pt-BR", {
    hour: "2-digit",
    minute: "2-digit",
  })
}
