/**
 * instanceStore.ts — Gerencia instâncias WhatsApp e QR Codes.
 * Separado do chatStore para responsabilidade única.
 */
import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'
import { instanceApi } from '../services/chatApiService'
import { socketService } from '../services/socketService'
import { notify } from './notificationStore'

export type InstanceStatus = 'DISCONNECTED' | 'CONNECTING' | 'QR_PENDING' | 'CONNECTED' | 'BANNED'

export interface Instance {
  id: string
  name: string
  status: InstanceStatus
  phone: string | null
  avatar: string | null
}

interface InstanceState {
  instances: Instance[]
  activeInstanceId: string | null
  qrByInstance: Record<string, string>
  loading: boolean

  // Sync actions
  setInstances: (instances: Instance[]) => void
  setActiveInstance: (id: string | null) => void
  patchInstance: (id: string, patch: Partial<Instance>) => void
  setQr: (instanceId: string, qrBase64: string) => void
  clearQr: (instanceId: string) => void
  removeInstance: (id: string) => void

  // Async actions
  loadInstances: () => Promise<void>
  connectInstance: (id: string) => Promise<void>
  disconnectInstance: (id: string) => Promise<void>
  createInstance: (name: string) => Promise<Instance>
  deleteInstance: (id: string) => Promise<void>

  // Socket
  initSocketListeners: () => void
}

export const useInstanceStore = create<InstanceState>()(
  immer((set, get) => ({
    instances: [],
    // Persiste a seleção ativa no localStorage para sobreviver a reloads
    activeInstanceId: typeof window !== 'undefined' ? localStorage.getItem('activeInstanceId') : null,
    qrByInstance: {},
    loading: false,

    // ── Sync ─────────────────────────────────────────────────────────────────

    setInstances: (instances) =>
      set((s) => { s.instances = instances }),

    setActiveInstance: (id) => {
      if (typeof window !== 'undefined') {
        if (id) localStorage.setItem('activeInstanceId', id)
        else localStorage.removeItem('activeInstanceId')
      }
      set((s) => { s.activeInstanceId = id })
    },

    patchInstance: (id, patch) =>
      set((s) => {
        const idx = s.instances.findIndex((i) => i.id === id)
        if (idx !== -1) Object.assign(s.instances[idx], patch)
        else s.instances.push({ id, name: '', phone: null, status: 'CONNECTING', ...patch } as Instance)
      }),

    setQr: (instanceId, qrBase64) =>
      set((s) => { s.qrByInstance[instanceId] = qrBase64 }),

    clearQr: (instanceId) =>
      set((s) => { delete s.qrByInstance[instanceId] }),

    removeInstance: (id) =>
      set((s) => { s.instances = s.instances.filter((i) => i.id !== id) }),

    // ── Async ─────────────────────────────────────────────────────────────────

    loadInstances: async () => {
      set((s) => { s.loading = true })
      try {
        const data = await instanceApi.list()
        const list: Instance[] = (Array.isArray(data) ? data : (data.instances ?? [])).map((i: any) => ({
          ...i,
          avatar: i.avatar ?? null,
        }))
        set((s) => {
          s.loading = false
          // Mescla em vez de substituir: preserva status CONNECTED que veio via socket
          // (socket events são mais recentes que leituras REST — o banco pode estar
          // desatualizado se a resposta da API chegou antes do DB ser gravado pelo backend)
          const memMap = new Map(s.instances.map((i) => [i.id, i]))
          s.instances = list.map((fromDb) => {
            const inMem = memMap.get(fromDb.id)
            if (inMem?.status === 'CONNECTED' && fromDb.status !== 'CONNECTED') {
              // Socket já confirmou CONNECTED — mantém, não deixa REST stale sobrescrever
              return { ...fromDb, status: 'CONNECTED' as InstanceStatus }
            }
            return fromDb
          })
        })
      } catch {
        set((s) => { s.loading = false })
      }
    },

    connectInstance: async (id) => {
      get().patchInstance(id, { status: 'CONNECTING' })
      socketService.joinInstance(id)
      await instanceApi.connect(id)
    },

    disconnectInstance: async (id) => {
      await instanceApi.disconnect(id)
      get().patchInstance(id, { status: 'DISCONNECTED' })
      get().clearQr(id)
    },

    createInstance: async (name) => {
      const created: Instance = await instanceApi.create(name)
      set((s) => { s.instances.push(created) })
      return created
    },

    deleteInstance: async (id) => {
      await instanceApi.delete(id)
      get().removeInstance(id)
      if (get().activeInstanceId === id) {
        set((s) => { s.activeInstanceId = null })
      }
    },

    // ── Socket ────────────────────────────────────────────────────────────────

    initSocketListeners: () => {
      socketService.on('instance:status', ({
        instanceId,
        status,
        qrBase64,
      }: {
        instanceId: string
        status: InstanceStatus
        qrBase64?: string
      }) => {
        get().patchInstance(instanceId, { status })
        if (qrBase64) get().setQr(instanceId, qrBase64)
        if (status === 'CONNECTED') get().clearQr(instanceId)
      })

      socketService.on('qr', ({ instanceId, qrBase64 }: { instanceId: string; qrBase64: string }) => {
        get().setQr(instanceId, qrBase64)
        get().patchInstance(instanceId, { status: 'QR_PENDING' })
      })

      socketService.on('instance:avatar', ({ instanceId, avatar }: { instanceId: string; avatar: string }) => {
        get().patchInstance(instanceId, { avatar })
      })

      socketService.on('instance:syncing', ({ instanceId, gapMinutes }: { instanceId: string; gapMinutes: number }) => {
        const inst = get().instances.find((i) => i.id === instanceId)
        const label = inst?.name ?? instanceId.slice(0, 8)
        if (gapMinutes >= 60) {
          notify(
            `📥 ${label}: sincronizando mensagens dos últimos ${Math.round(gapMinutes / 60)}h`,
            'warning',
            8000,
            'syncing',
          )
        } else if (gapMinutes > 0) {
          notify(
            `📥 ${label}: buscando mensagens perdidas (${gapMinutes} min offline)`,
            'info',
            6000,
            'syncing',
          )
        }
      })
    },
  }))
)
