/**
 * 连接管理器 — 管理本地/远程/SFTP 传输层切换
 * 配置持久化：SQLite（后端），local profile 仅内存
 */

import type { FsTransport } from './transport'
import { WailsTransport } from './wails-transport'
import { HttpTransport } from './http-transport'
import { SftpTransport } from './sftp-transport'
import { getFileServerBaseURL } from './file-server'
import {
  LoadConnectionProfiles, SaveConnectionProfile, DeleteConnectionProfile,
  SftpGetSystemInfo, GetLocalSystemInfo,
} from '@bindings/u-desk/app'

export type ConnectionType = 'local' | 'remote' | 'sftp'

export interface ConnectionProfile {
  id: string | number
  name: string
  host: string
  port: number
  token: string
  type: ConnectionType
  username?: string
  password?: string
  keyPath?: string
  lastConnected?: number
}

export type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'error'

export interface SystemInfo {
  cpuCores?: number
  cpuUsage?: string
  memTotal?: number
  memUsed?: number
  memUsage?: string
  diskTotal?: number
  diskUsed?: number
  diskUsage?: string
  _error?: boolean
  _errorMsg?: string
}

class ConnectionManagerImpl {
  /** 连接池：profileId → transport 实例 */
  private _pool = new Map<string, FsTransport>()
  private _profiles: ConnectionProfile[] = []
  private _activeId: string | null = null
  private _state: ConnectionState = 'disconnected'
  private _stateChangeCallbacks: ((state: ConnectionState) => void)[] = []
  private _sysInfoChangeCallbacks: ((profileId: string, info: SystemInfo) => void)[] = []
  private _sysInfoCache = new Map<string, SystemInfo>()

  constructor() {
    this.initDefaultLocal()
    this.loadFromDB()
  }

  private initDefaultLocal() {
    const localProfile: ConnectionProfile = {
      id: 'local-default',
      name: '本地',
      host: '',
      port: 0,
      token: '',
      type: 'local',
    }
    if (!this._profiles.find(p => p.id === localProfile.id)) {
      this._profiles.unshift(localProfile)
    }
    if (!this._activeId) {
      this._activeId = localProfile.id
    }
    // local 直接入池，无需连接
    this._pool.set('local-default', new WailsTransport())
    this.setState('connected')
  }

  /** 从 SQLite 加载配置 */
  private async loadFromDB() {
    try {
      const list = await LoadConnectionProfiles()
      if (list && list.length > 0) {
        this._profiles = list.map((p: any) => ({
          ...p,
          id: String(p.id),
          lastConnected: p.lastConnected || p.last_connected ? new Date(p.lastConnected || p.last_connected).getTime() : undefined,
        }))
        const hasLocal = this._profiles.some(p => p.type === 'local')
        if (!hasLocal) {
          this._profiles.unshift({
            id: 'local-default', name: '本地', host: '', port: 0, token: '', type: 'local',
          })
        }
      }
    } catch { /* 首次使用 */ }
    this.notifyChange()
    this._profiles.forEach(p => {
      if (p.type === 'local') { this.fetchSystemInfo(p.id).catch(() => {}) }
    })
    const autoConnect = localStorage.getItem('desk:autoConnect')
    if (autoConnect !== 'false') {
      for (const p of this._profiles) {
        if (p.type !== 'local') {
          this.buildAndPool(String(p.id), p).catch(() => {})
        }
      }
    }
  }

  /** 保存/更新单个 profile 到 SQLite */
  private async persistProfile(profile: ConnectionProfile) {
    if (profile.type === 'local') return
    const id = profile.id !== 'local-default' ? Number(profile.id) : 0
    await SaveConnectionProfile({
      id: id > 0 ? id : undefined,
      name: profile.name,
      host: profile.host,
      port: profile.port,
      username: profile.username || 'root',
      password: profile.password || '',
      keyPath: profile.keyPath || '',
      type: profile.type,
      token: profile.token || '',
      lastConnected: profile.lastConnected ? Math.floor(profile.lastConnected / 1000) : undefined,
    })
  }

  /** 从 SQLite 删除 profile */
  private async removePersisted(id: string) {
    if (id === 'local-default') return
    await DeleteConnectionProfile(Number(id))
  }

  private setState(state: ConnectionState) {
    this._state = state
    this.notifyChange()
  }

  private notifyChange() {
    this._stateChangeCallbacks.forEach(cb => cb(this._state))
  }

  onStateChange(cb: (state: ConnectionState) => void) {
    this._stateChangeCallbacks.push(cb)
  }

  onSystemInfoChange(cb: (profileId: string, info: SystemInfo) => void) {
    this._sysInfoChangeCallbacks.push(cb)
  }

  get state(): ConnectionState { return this._state }

  get profiles(): ConnectionProfile[] { return [...this._profiles] }

  get activeProfile(): ConnectionProfile | null {
    return this._profiles.find(p => p.id === this._activeId) ?? null
  }

  /** 获取当前激活的 transport（从池中取） */
  getTransport(): FsTransport {
    if (this._activeId && this._pool.has(this._activeId)) {
      return this._pool.get(this._activeId)!
    }
    return this._pool.get('local-default')!
  }

  /** 获取指定 profile 的 transport（用于跨 profile 操作如采集系统信息） */
  getTransportFor(profileId: string): FsTransport | null {
    return this._pool.get(profileId) ?? null
  }

  getFileServerBaseURL(): string {
    const t = this.getTransport()
    if (t instanceof HttpTransport) {
      const profile = this.activeProfile
      if (!profile) return ''
      const scheme = profile.port === 443 ? 'https' : 'http'
      const port = (profile.port === 80 || profile.port === 443) ? '' : `:${profile.port}`
      return `${scheme}://${profile.host}${port}`
    }
    if (t instanceof SftpTransport) { return getFileServerBaseURL() }
    return ''
  }

  isSftp(): boolean { return this.activeProfile?.type === 'sftp' }

  isRemote(): boolean {
    const t = this.activeProfile?.type
    return t === 'remote' || t === 'sftp'
  }

  getSystemInfo(profileId: string): SystemInfo | undefined {
    return this._sysInfoCache.get(profileId)
  }

  async fetchSystemInfo(profileId: string): Promise<SystemInfo> {
    const profile = this._profiles.find(p => p.id === profileId)
    if (!profile) return { _error: true }
    const info: SystemInfo = {}
    try {
      if (profile.type === 'local') {
        const data = await GetLocalSystemInfo()
        if (data) Object.assign(info, data)
      } else if (profile.type === 'sftp') {
        const t = this.getTransportFor(profileId)
        if (t instanceof SftpTransport && t.sessionId) {
          const data = await SftpGetSystemInfo(t.sessionId)
          if (data) Object.assign(info, snakeToCamel(data))
        }
      } else if (profile.type === 'remote') {
        const t = this.getTransportFor(profileId)
        if (t instanceof HttpTransport) {
          const baseUrl = this.getFileServerBaseURL()
          if (baseUrl) {
            const token = profile.token || ''
            const headers: Record<string, string> = { 'Content-Type': 'application/json' }
            if (token) headers['Authorization'] = `Bearer ${token}`
            const res = await fetch(`${baseUrl}/api/v1/system/stats`, { headers })
            if (res.ok) {
              const json = await res.json()
              const data = json.data ?? json
              if (data) Object.assign(info, snakeToCamel(data))
            }
          }
        }
      }
    } catch (e) { info._error = true; info._errorMsg = e instanceof Error ? e.message : String(e) }

    this._sysInfoCache.set(profileId, info)
    this._sysInfoChangeCallbacks.forEach(cb => cb(profileId, info))
    return info
  }

  /**
   * 切换到指定 profile（连接池模式）
   * 池中有 → 直接复用，瞬间切换
   * 池中无   → 新建连接并存入池
   */
  async connect(profileId: string): Promise<void> {
    const profile = this._profiles.find(p => p.id === profileId)
    if (!profile) return Promise.reject(new Error(`连接配置不存在: ${profileId}`))

    this._activeId = profileId

    // 池中已有，直接复用
    if (this._pool.has(profileId)) {
      this.setState('connected')
      return
    }

    // 新建连接并入池
    await this.buildAndPool(profileId, profile)
  }

  /** 断开指定 profile 并从池移除 */
  disconnectProfile(profileId: string): void {
    if (profileId === 'local-default') return
    const t = this._pool.get(profileId)
    if (t instanceof SftpTransport) { t.disconnect() }
    this._pool.delete(profileId)
  }

  /** 断开所有远程连接（保留 local） */
  disconnectAll(): void {
    for (const [id, t] of this._pool) {
      if (id !== 'local-default' && t instanceof SftpTransport) {
        t.disconnect()
      }
    }
    this._pool.clear()
    this._pool.set('local-default', new WailsTransport())
    this._activeId = 'local-default'
    this.setState('connected')
  }

  disconnect(): void {
    this.disconnectAll()
  }

  async addProfile(profile: Omit<ConnectionProfile, 'id'>): Promise<ConnectionProfile> {
    const newProfile: ConnectionProfile = { ...profile, id: crypto.randomUUID() }
    this._profiles.push(newProfile)
    await this.persistProfile(newProfile)
    this.notifyChange()
    return newProfile
  }

  async updateProfile(id: string, updates: Partial<ConnectionProfile>): Promise<void> {
    const idx = this._profiles.findIndex(p => p.id === id)
    if (idx >= 0) {
      this._profiles[idx] = { ...this._profiles[idx], ...updates }
      await this.persistProfile(this._profiles[idx])
      // 连接参数变更 → 淘汰旧连接，下次 connect 时重建
      const EVICT_KEYS = ['host', 'port', 'token', 'username', 'password', 'keyPath'] as const
      if (EVICT_KEYS.some(k => k in updates)) {
        this.disconnectProfile(id)
        if (id === this._activeId) {
          this.connect(id).catch(err => console.warn('[SFTP] 编辑后重连失败:', err))
        }
      }
      this.notifyChange()
    }
  }

  async removeProfile(id: string): Promise<void> {
    if (id === 'local-default') return
    this._profiles = this._profiles.filter(p => p.id !== id)
    this.disconnectProfile(id)
    if (this._activeId === id) {
      this._activeId = 'local-default'
      this.setState('connected')
    }
    await this.removePersisted(id)
    this.notifyChange()
  }

  /** 新建 transport 并存入连接池 */
  private async buildAndPool(profileId: string, profile: ConnectionProfile): Promise<void> {
    if (profile.type === 'local') {
      this._pool.set(profileId, new WailsTransport())
      this.setState('connected')
      return
    }

    if (profile.type === 'sftp') {
      if (!profile.password && !profile.keyPath) {
        this._pool.set(profileId, new WailsTransport())
        this.setState('error')
        return
      }
      this.setState('connecting')
      try {
        const t = new SftpTransport(profile)
        await t.connect()
        this._pool.set(profileId, t)
        this.setState('connected')
        this.updateProfile(profileId, { lastConnected: Date.now() })
        this.fetchSystemInfo(profileId).catch(() => {})
      } catch (err) {
        this._pool.delete(profileId)
        this.setState('error')
        throw err
      }
      return
    }

    // remote / http agent
    this.setState('connecting')
    try {
      const t = new HttpTransport(profile.host, profile.port, profile.token)
      this._pool.set(profileId, t)
      // 验证连接可用性
      t.getFileInfo('/').then(() => {
        if (this._activeId !== profileId) return
        this.setState('connected')
        this.updateProfile(profileId, { lastConnected: Date.now() })
        this.fetchSystemInfo(profileId).catch(() => {})
      }).catch(() => {
        if (this._activeId !== profileId) return
        this.setState('error')
      })
    } catch (err) {
      this._pool.delete(profileId)
      this.setState('error')
      throw err
    }
  }
}

export const connectionManager = new ConnectionManagerImpl()

/** snake_case → camelCase */
function snakeToCamel(obj: Record<string, any>): Record<string, any> {
  const result: Record<string, any> = {}
  for (const [k, v] of Object.entries(obj)) {
    result[k.replace(/_([a-z])/g, (_, c) => c.toUpperCase())] = v
  }
  return result
}
