import { invoke } from '@tauri-apps/api/core'
import { listen, type UnlistenFn } from '@tauri-apps/api/event'
import type {
  AccountQuota,
  AgentInfo,
  BuiltinAgentInfo,
  ApiEndpoint,
  ApiStatus,
  Category,
  ClaudePathInfo,
  CommandItem,
  Config,
  FilePreviewData,
  FsEntry,
  HookEventPayload,
  IndexStatus,
  InjectedRule,
  McpServers,
  ModelInfo,
  OpenProjectPayload,
  PreviewMessage,
  RequestLog,
  RouteRule,
  RouterConfig,
  RouterStatus,
  RouterView,
  RuleItem,
  SearchHit,
  SessionInfo,
  SessionMeta,
  Settings,
  UsageBucket,
  UsageStats,
  WechatInbound,
  WechatStatus
} from './types'

// ---------- 配置与项目 ----------

export const getConfig = () => invoke<Config>('get_config')
export const takePendingOpen = () => invoke<OpenProjectPayload | null>('take_pending_open')
export const updateSettings = (settings: Settings) => invoke<Config>('update_settings', { settings })
export const addProject = (path: string) => invoke<Config>('add_project', { path })
export const removeProject = (path: string) => invoke<Config>('remove_project', { path })

// ---------- 会话 ----------

export const listSessions = (projectPath: string) =>
  invoke<SessionInfo[]>('list_sessions', { projectPath })
export const previewSession = (projectPath: string, sessionId: string) =>
  invoke<PreviewMessage[]>('preview_session', { projectPath, sessionId })
export const deleteSession = (projectPath: string, sessionId: string) =>
  invoke<void>('delete_session', { projectPath, sessionId })
export const renameSession = (sessionId: string, title: string) =>
  invoke<Config>('rename_session', { sessionId, title })
export const searchSessions = (projectPath: string | null, query: string) =>
  invoke<SearchHit[]>('search_sessions', { projectPath, query })

// ---------- 终端 ----------

export const ptySpawn = (tabId: string, cwd: string, args: string[], cols: number, rows: number) =>
  invoke<void>('pty_spawn', { tabId, cwd, args, cols, rows })
export const ptyWrite = (tabId: string, data: string) => invoke<void>('pty_write', { tabId, data })
export const ptyResize = (tabId: string, cols: number, rows: number) =>
  invoke<void>('pty_resize', { tabId, cols, rows })
export const ptyKill = (tabId: string) => invoke<void>('pty_kill', { tabId })

// ---------- 指令库 ----------

export const saveCommand = (item: CommandItem) => invoke<Config>('save_command', { item })
export const deleteCommand = (id: string) => invoke<Config>('delete_command', { id })
export const saveCommandCategory = (category: Category) =>
  invoke<Config>('save_command_category', { category })
export const deleteCommandCategory = (id: string) =>
  invoke<Config>('delete_command_category', { id })

// ---------- 规则库 ----------

export const saveRule = (item: RuleItem) => invoke<Config>('save_rule', { item })
export const deleteRule = (id: string) => invoke<Config>('delete_rule', { id })
export const saveRuleCategory = (category: Category) =>
  invoke<Config>('save_rule_category', { category })
export const deleteRuleCategory = (id: string) => invoke<Config>('delete_rule_category', { id })

// ---------- 项目规则注入 ----------

export const listInjectedRules = (projectPath: string) =>
  invoke<InjectedRule[]>('list_injected_rules', { projectPath })
export const injectRule = (projectPath: string, ruleId: string) =>
  invoke<string>('inject_rule', { projectPath, ruleId })
export const setRuleEnabled = (projectPath: string, slug: string, enabled: boolean) =>
  invoke<void>('set_rule_enabled', { projectPath, slug, enabled })
export const removeInjectedRule = (projectPath: string, slug: string) =>
  invoke<void>('remove_injected_rule', { projectPath, slug })
export const readInjectedRule = (projectPath: string, slug: string) =>
  invoke<string>('read_injected_rule', { projectPath, slug })
export const readClaudeMd = (projectPath: string) => invoke<string>('read_claudemd', { projectPath })
export const writeClaudeMd = (projectPath: string, content: string) =>
  invoke<void>('write_claudemd', { projectPath, content })
export const ruleSlug = (name: string) => invoke<string>('rule_slug', { name })

// ---------- 系统集成 ----------

export const installContextMenu = () => invoke<void>('install_context_menu')
export const uninstallContextMenu = () => invoke<void>('uninstall_context_menu')
export const contextMenuStatus = () => invoke<boolean>('context_menu_status')
export const installHooks = () => invoke<void>('install_hooks')
export const uninstallHooks = () => invoke<void>('uninstall_hooks')
export const hooksStatus = () => invoke<boolean>('hooks_status')
export const claudePathInfo = () => invoke<ClaudePathInfo>('claude_path_info')
export const claudePathTest = () => invoke<string>('claude_path_test')
export const activeSessionCount = () => invoke<number>('active_session_count')
export const claudeUpdate = () => invoke<string>('claude_update')

// ---------- 文件树与剪贴板 ----------

export const fsListDir = (path: string) => invoke<FsEntry[]>('fs_list_dir', { path })
export const clipboardSetText = (text: string) =>
  invoke<void>('clipboard_set_text', { text }).catch((e) => {
    // 重试到底仍失败(剪贴板被其他软件长时间抢占)时不再静默吞错,留痕便于排查
    console.warn('剪贴板写入失败:', e)
  })
export const clipboardGetText = () => invoke<string | null>('clipboard_get_text')
export const clipboardImageToTemp = () => invoke<string | null>('clipboard_image_to_temp')
export const relativePath = (base: string, path: string) =>
  invoke<string>('relative_path', { base, path })
export const revealInExplorer = (path: string) => invoke<void>('reveal_in_explorer', { path })

// ---------- 用量统计 ----------

export const usageStats = (dayStartMs: number, weekStartMs: number, monthStartMs: number) =>
  invoke<UsageStats>('usage_stats', { dayStartMs, weekStartMs, monthStartMs })
export const accountQuota = () => invoke<AccountQuota>('account_quota')
export const listModels = () => invoke<ModelInfo[]>('list_models')
export const sessionMeta = (projectPath: string, sessionId: string) =>
  invoke<SessionMeta>('session_meta', { projectPath, sessionId })
/** 取某会话最近一条回复文本（截断 maxChars），供微信"查看输出" */
export const lastAssistant = (projectPath: string, sessionId: string, maxChars: number) =>
  invoke<string>('last_assistant', { projectPath, sessionId, maxChars })
/** 最近一个待处理工具调用（AskUserQuestion/权限确认），供微信端结构化展示选项 */
export interface LastToolUse {
  name: string
  input: unknown
}
export const lastToolUse = (projectPath: string, sessionId: string) =>
  invoke<LastToolUse | null>('last_tool_use', { projectPath, sessionId })
export const usageTrend = (todayStartMs: number, days: number) =>
  invoke<UsageBucket[]>('usage_trend', { todayStartMs, days })
export const exportSession = (projectPath: string, sessionId: string, title: string, dest: string) =>
  invoke<void>('export_session', { projectPath, sessionId, title, dest })

// ---------- 文件操作与监听 ----------

export const fsReadPreview = (path: string) => invoke<FilePreviewData>('fs_read_preview', { path })
export const fsWriteText = (path: string, content: string, expectedMtimeMs: number) =>
  invoke<number>('fs_write_text', { path, content, expectedMtimeMs })
export const fsCreate = (path: string, isDir: boolean) => invoke<void>('fs_create', { path, isDir })
export const fsRename = (path: string, newName: string) =>
  invoke<string>('fs_rename', { path, newName })
export const fsDelete = (path: string) => invoke<void>('fs_delete', { path })
export const fsWatch = (projectPath: string) => invoke<void>('fs_watch', { projectPath })
export const onFsChanged = (cb: () => void): Promise<UnlistenFn> =>
  listen('fs-changed', () => cb())

// ---------- MCP 服务器 ----------

export const mcpList = (projectPath: string | null) =>
  invoke<McpServers>('mcp_list', { projectPath })
export const mcpSave = (
  scope: 'global' | 'project',
  projectPath: string | null,
  name: string,
  serverJson: string
) => invoke<void>('mcp_save', { scope, projectPath, name, serverJson })
export const mcpDelete = (scope: 'global' | 'project', projectPath: string | null, name: string) =>
  invoke<void>('mcp_delete', { scope, projectPath, name })

// ---------- 代码索引 ----------

export const indexStatus = (projectPath: string) =>
  invoke<IndexStatus>('index_status', { projectPath })
export const indexRebuild = (projectPath: string) =>
  invoke<void>('index_rebuild', { projectPath })

// ---------- 微信 ClawBot ----------

export const wechatStatus = () => invoke<WechatStatus>('wechat_status')
/** 开始扫码登录，返回二维码 data URL 供前端立即显示 */
export const wechatStartLogin = () => invoke<string>('wechat_start_login')
export const wechatUnbind = () => invoke<void>('wechat_unbind')
/** 给操作人发一条消息（出站通知/回复）；未绑定或未激活时后端静默跳过 */
export const wechatSendNotice = (text: string) => invoke<void>('wechat_send_notice', { text })

// ---------- 移动端网关 ----------

export interface MobileStatus {
  enabled: boolean
  port: number
  token: string
  localIps: string[]
  connCount: number
  /** 公网中继拨出是否开启 */
  relayEnabled: boolean
  /** 中继地址（wss://...） */
  relayUrl: string
  /** 本机房间号（配对码的一部分） */
  relayRoom: string
  /** 中继当前是否已拨通 */
  relayOnline: boolean
}
export interface MobileSessionMeta {
  tabId: string
  sessionId: string
  projectPath: string
  title: string
  status: string
  model?: string
}
export const mobileStatus = () => invoke<MobileStatus>('mobile_status')
export const mobilePairingUrl = () => invoke<string>('mobile_pairing_url')
/** 公网中继配对链接：https://relay.域名/?room=..&token=..（手机打开即自动连回本机） */
export const mobileRelayPairingUrl = () => invoke<string>('mobile_relay_pairing_url')
export const mobileUnbind = () => invoke<void>('mobile_unbind')
export const mobilePublishSessions = (sessions: MobileSessionMeta[]) =>
  invoke<void>('mobile_publish_sessions', { sessions })
/** 把结构化选项 / 状态等广播给已连接的移动端 App */
export const mobilePush = (payload: unknown) => invoke<void>('mobile_push', { payload })

// ---------- 公网隧道 ----------

export interface TunnelEntry {
  id: string
  subdomain: string
  localPort: number
  enabled: boolean
  /** 中继确认已激活（启用 + 在线 + 未冲突） */
  active: boolean
  /** 前缀被别的在线桌面占用 */
  conflict: boolean
  /** 公网地址 https://<前缀>.<基域>/ */
  url: string
}
export interface TunnelStatus {
  /** 隧道总开关 */
  enabled: boolean
  /** 是否已开启公网中继（隧道页可用的前提） */
  relayEnabled: boolean
  /** 是否已拨通中继 */
  online: boolean
  /** 是否已设置注册密钥 */
  secretSet: boolean
  /** 基域（由中继地址派生） */
  baseDomain: string
  entries: TunnelEntry[]
}
export const tunnelStatus = () => invoke<TunnelStatus>('tunnel_status')
export const tunnelSetMaster = (enabled: boolean) => invoke<TunnelStatus>('tunnel_set_master', { enabled })
export const tunnelSetSecret = (secret: string) => invoke<TunnelStatus>('tunnel_set_secret', { secret })
export const tunnelAdd = (subdomain: string, localPort: number) =>
  invoke<TunnelStatus>('tunnel_add', { subdomain, localPort })
export const tunnelUpdate = (id: string, subdomain: string, localPort: number) =>
  invoke<TunnelStatus>('tunnel_update', { id, subdomain, localPort })
export const tunnelRemove = (id: string) => invoke<TunnelStatus>('tunnel_remove', { id })
export const tunnelToggle = (id: string, enabled: boolean) =>
  invoke<TunnelStatus>('tunnel_toggle', { id, enabled })

// ---------- API 注入（Claude Code 全局模型接口） ----------

export const apiInjectStatus = () => invoke<ApiStatus>('api_inject_status')
export const apiInjectList = () => invoke<ApiEndpoint[]>('api_inject_list')
export const apiInjectSave = (endpoint: ApiEndpoint) =>
  invoke<ApiEndpoint[]>('api_inject_save', { endpoint })
export const apiInjectDelete = (id: string) => invoke<ApiEndpoint[]>('api_inject_delete', { id })
export const apiInjectFetchModels = (baseUrl: string, key: string) =>
  invoke<ModelInfo[]>('api_inject_fetch_models', { baseUrl, key })
/** 当前注入态下的可选模型清单：router=本地聚合，direct=实时拉取当前接口 */
export const apiInjectActiveModels = () => invoke<ModelInfo[]>('api_inject_active_models')
export const apiInjectApply = (id: string) => invoke<void>('api_inject_apply', { id })
export const apiInjectReset = () => invoke<void>('api_inject_reset')
/** 内置虚拟路由接口 id：注入后 settings 指向本地多模型路由代理 */
export const ROUTER_ENDPOINT_ID = 'builtin:router'
export const apiInjectRouterGet = () => invoke<RouterView>('api_inject_router_get')
export const apiInjectRouterSave = (config: RouterConfig, routes: RouteRule[]) =>
  invoke<void>('api_inject_router_save', { config, routes })
export const routerStatus = () => invoke<RouterStatus>('router_status')
export const routerLogs = () => invoke<RequestLog[]>('router_logs')

// ---------- Agents 管理（列表 + model 指派） ----------

export const agentsList = (projectPath?: string) =>
  invoke<AgentInfo[]>('agents_list', { projectPath: projectPath ?? null })
export const agentsSetModel = (path: string, model: string) =>
  invoke<void>('agents_set_model', { path, model })
export const agentsCreate = (opts: {
  scope: 'global' | 'project'
  projectPath?: string
  name: string
  description: string
  model: string
  prompt: string
}) => invoke<string>('agents_create', { ...opts, projectPath: opts.projectPath ?? null })
/** 内置 agent 类型及其覆盖状态（同名覆盖文件，项目级优先） */
export const agentsBuiltinList = (projectPath?: string) =>
  invoke<BuiltinAgentInfo[]>('agents_builtin_list', { projectPath: projectPath ?? null })
/** 为内置类型指派模型：已有覆盖改 model，无覆盖则生成同名覆盖文件 */
export const agentsSetBuiltinModel = (opts: {
  scope: 'global' | 'project'
  projectPath?: string
  name: string
  model: string
}) => invoke<void>('agents_set_builtin_model', { ...opts, projectPath: opts.projectPath ?? null })
/** 删除 agent 定义文件（含内置类型的覆盖文件 → 恢复内置） */
export const agentsDelete = (path: string) => invoke<void>('agents_delete', { path })
/** 立即重启应用（注入/重置后生效） */
export const restartApp = () => invoke<void>('restart_app')

// ---------- 事件 ----------

export interface PtyDataPayload {
  tabId: string
  data: string // base64
}

export interface PtyExitPayload {
  tabId: string
  exitCode: number
}

export const onPtyData = (cb: (p: PtyDataPayload) => void): Promise<UnlistenFn> =>
  listen<PtyDataPayload>('pty-data', (e) => cb(e.payload))
export const onPtyExit = (cb: (p: PtyExitPayload) => void): Promise<UnlistenFn> =>
  listen<PtyExitPayload>('pty-exit', (e) => cb(e.payload))
export const onOpenProject = (cb: (p: OpenProjectPayload) => void): Promise<UnlistenFn> =>
  listen<OpenProjectPayload>('open-project', (e) => cb(e.payload))
export const onSessionStatus = (cb: (p: HookEventPayload) => void): Promise<UnlistenFn> =>
  listen<HookEventPayload>('session-status', (e) => cb(e.payload))
export const onWechatInbound = (cb: (p: WechatInbound) => void): Promise<UnlistenFn> =>
  listen<WechatInbound>('wechat-inbound', (e) => cb(e.payload))

/** 移动端 App 入站遥控（对称于 wechat-inbound）：控制面动作交前端复用编排 */
export interface MobileInbound {
  kind: 'new' | 'resume' | 'close' | 'answer' | 'serialize' | 'projectAdded'
  /** projectAdded：新增项目的规范化路径（其余字段按 kind 各自使用） */
  path?: string
  projectPath?: string
  sessionId?: string
  tabId?: string
  model?: string
  permissionMode?: string
  extraArgs?: string
  promptId?: string
  choice?: string
  /** serialize：请求方（手机）连接 id，序列化结果定向回传给它 */
  connId?: number
}
export const onMobileInbound = (cb: (p: MobileInbound) => void): Promise<UnlistenFn> =>
  listen<MobileInbound>('mobile-inbound', (e) => cb(e.payload))
/** 把桌面序列化好的完整回看缓冲，定向发给发起 attach 的那个手机连接 */
export const mobileSnapshot = (connId: number, tabId: string, data: string) =>
  invoke<void>('mobile_snapshot', { connId, tabId, data })
