import {
  DEFAULT_SETTINGS,
  type Settings,
  type CommandTemplate,
  type MediaProfile,
  type FfmpegSetupProgress
} from '@shared/ipc'

/**
 * The browser-preview stand-in for the real `window.api` IPC bridge (C1). In the
 * standalone UI preview (browser, no Electron preload) `window.api` isn't
 * injected, so main.tsx assigns this mock to keep the UI interactive during
 * design work. Typed as the real `Api` surface (`Window['api']`) so it can't
 * silently drift from the preload contract — a missing or mistyped method is a
 * compile error. Most methods are inert no-ops because the stores detect preview
 * mode (no window.electron) and drive a fake progress ticker instead.
 */
type Api = Window['api']

// The preview settings: the canonical defaults, plus preview-only tweaks —
// placeholder folders, a nightly channel + a recent check to exercise the
// updater card, auto-download on, and onboarding already dismissed so design
// work isn't blocked behind the welcome screen.
const MOCK_SETTINGS: Settings = {
  ...DEFAULT_SETTINGS,
  videoFolder: 'C:\\Users\\you\\Documents\\Video',
  audioFolder: 'C:\\Users\\you\\Documents\\Audio',
  ytdlpChannel: 'nightly',
  ytdlpLastUpdateCheck: Date.now() - 3_600_000,
  autoDownloadNew: true,
  hasCompletedOnboarding: true
}

// One mock "installed version" so the sidebar (getAppVersion) and the update card
// (checkForAppUpdate.currentVersion) agree instead of disagreeing 0.4.0-preview vs
// 0.4.0 (L171). Kept below the mock "latest" so the updater card demos an available
// update in the browser preview.
const MOCK_CURRENT_VERSION = '0.4.0'

// Stands in for the cookies.txt file's mtime — lets the Cookies card's
// sign-in/clear flow be exercised in this browser-only preview.
let mockCookiesSavedAt: number | null = null
// Stands in for templates.json — lets the Custom commands card's CRUD and
// the download bar's template picker be exercised in this browser-only preview.
let mockTemplates: CommandTemplate[] = [
  { id: 'tpl1', name: 'Write thumbnail, no mtime', args: '--write-thumbnail --no-mtime' }
]

let mockProfiles: MediaProfile[] = [
  { id: 'p1', name: 'Archive (1080p, subs)', kind: 'video', quality: '1080p' },
  { id: 'p2', name: 'Music (audio only)', kind: 'audio', quality: 'Best' }
]

// First-run ffmpeg setup preview state: ready unless `?setup` is in the preview URL (which
// forces the onboarding setup step), plus the progress callback the fake download drives.
let mockFfmpegReady = typeof location === 'undefined' || !/[?&]setup(\b|=)/.test(location.search)
let mockFfmpegProgressCb: ((p: FfmpegSetupProgress) => void) | null = null

export const mockApi: Api = {
  getAppVersion: async () => MOCK_CURRENT_VERSION,
  checkForAppUpdate: async () => {
    await new Promise((r) => setTimeout(r, 400))
    return {
      ok: true,
      available: true,
      currentVersion: MOCK_CURRENT_VERSION,
      latestVersion: '0.5.0',
      notes:
        '### What’s new in v0.5.0\n- In-app updater (this screen!)\n- Faster downloads\n- Bug fixes',
      htmlUrl: 'https://gitea.netbird.zimspace.uk:5938/debont80/AeroFetch/releases',
      downloadUrl: 'https://gitea.netbird.zimspace.uk:5938/example/AeroFetch-Setup-0.5.0.exe',
      assetName: 'AeroFetch-Setup-0.5.0.exe'
    }
  },
  downloadAppUpdate: async () => ({
    ok: false,
    error: 'Downloading updates is disabled in the browser preview.'
  }),
  cancelAppUpdate: async () => {},
  runAppUpdate: async () => ({ ok: true }),
  onAppUpdateProgress: () => () => {},
  getYtdlpVersion: async () => ({ ok: true, version: '2025.06.01 (UI preview mock)' }),
  getFfmpegVersions: async () => ({
    ffmpeg: '8.1.2-essentials_build (UI preview mock)',
    ffprobe: '8.1.2-essentials_build (UI preview mock)'
  }),
  // First-run ffmpeg setup: ready by default so the preview isn't blocked. Append `?setup`
  // to the preview URL to force the not-ready state and demo the onboarding setup step —
  // the fake download/locate below then flips it ready.
  getFfmpegSetupStatus: async () =>
    mockFfmpegReady
      ? {
          ready: true,
          ffmpeg: '8.1.2-essentials_build (mock)',
          ffprobe: '8.1.2-essentials_build (mock)'
        }
      : { ready: false, ffmpeg: null, ffprobe: null },
  downloadFfmpeg: async () => {
    for (let i = 1; i <= 10; i++) {
      await new Promise((r) => setTimeout(r, 150))
      mockFfmpegProgressCb?.({
        phase: 'downloading',
        received: i * 11_000_000,
        total: 110_000_000,
        fraction: i / 10
      })
    }
    mockFfmpegProgressCb?.({ phase: 'extracting' })
    await new Promise((r) => setTimeout(r, 500))
    mockFfmpegReady = true
    return { ok: true }
  },
  cancelFfmpegDownload: async () => {},
  locateFfmpeg: async () => {
    mockFfmpegReady = true
    return { ok: true }
  },
  onFfmpegSetupProgress: (cb) => {
    mockFfmpegProgressCb = cb
    return () => {
      if (mockFfmpegProgressCb === cb) mockFfmpegProgressCb = null
    }
  },
  probe: async (url: string) => {
    await new Promise((r) => setTimeout(r, 700)) // simulate network latency
    // A 'list'/'playlist' URL exercises the playlist selection UI in preview.
    if (/list=|playlist/i.test(url)) {
      return {
        ok: true,
        kind: 'playlist',
        playlist: {
          title: 'Full Electron Course — All Episodes',
          uploader: 'DevChannel',
          count: 5,
          entries: Array.from({ length: 5 }, (_, i) => ({
            index: i + 1,
            id: `vid${i + 1}`,
            title: `Episode ${i + 1} — ${['Setup', 'Main Process', 'IPC', 'Packaging', 'Release'][i]}`,
            url: `https://youtube.com/watch?v=vid${i + 1}`,
            durationLabel: `${10 + i}:0${i}`,
            uploader: 'DevChannel'
          }))
        }
      }
    }
    return {
      ok: true,
      kind: 'video',
      info: {
        title: 'Building a Desktop App with Electron — Full Course',
        channel: 'DevChannel',
        durationLabel: '1:42:08',
        thumbnail: undefined,
        formats: [
          { id: '__best__', label: 'Best available', ext: 'mp4', hasAudio: true },
          {
            id: '299',
            label: '1080p60 · mp4 · 248 MB',
            height: 1080,
            ext: 'mp4',
            filesizeLabel: '248 MB',
            hasAudio: false
          },
          {
            id: '136',
            label: '720p · mp4 · 124 MB',
            height: 720,
            ext: 'mp4',
            filesizeLabel: '124 MB',
            hasAudio: false
          },
          {
            id: '135',
            label: '480p · mp4 · 72 MB',
            height: 480,
            ext: 'mp4',
            filesizeLabel: '72 MB',
            hasAudio: false
          },
          {
            id: '134',
            label: '360p · mp4 · 38 MB',
            height: 360,
            ext: 'mp4',
            filesizeLabel: '38 MB',
            hasAudio: false
          }
        ]
      }
    }
  },
  startDownload: async () => ({ ok: true }),
  cancelDownload: async () => {},
  pauseDownload: async () => {},
  chooseFolder: async () => null,
  openPath: async () => '',
  openUrl: async () => {},
  showInFolder: async () => '',
  readClipboard: async () => '',
  logError: () => {},
  getSettings: async () => MOCK_SETTINGS,
  setSettings: async (partial) => Object.assign(MOCK_SETTINGS, partial),
  listHistory: async () => [],
  addHistory: async () => [],
  removeHistory: async () => [],
  removeManyHistory: async () => [],
  clearHistory: async () => [],
  cookiesLogin: async () => {
    await new Promise((r) => setTimeout(r, 600)) // simulate the sign-in window
    mockCookiesSavedAt = Date.now()
    return { ok: true, cookieCount: 14 }
  },
  // Preview assumes the bundled aria2c is present, so the Network toggle renders
  // in its normal (enabled) state.
  aria2cAvailable: async () => true,
  cookiesStatus: async () =>
    mockCookiesSavedAt ? { exists: true, savedAt: mockCookiesSavedAt } : { exists: false },
  cookiesClear: async () => {
    mockCookiesSavedAt = null
  },
  listTemplates: async () => mockTemplates,
  saveTemplate: async (template) => {
    mockTemplates = [template, ...mockTemplates.filter((t) => t.id !== template.id)]
    return mockTemplates
  },
  removeTemplate: async (id) => {
    mockTemplates = mockTemplates.filter((t) => t.id !== id)
    return mockTemplates
  },
  listProfiles: async () => mockProfiles,
  saveProfile: async (profile) => {
    mockProfiles = [profile, ...mockProfiles.filter((p) => p.id !== profile.id)]
    return mockProfiles
  },
  removeProfile: async (id) => {
    mockProfiles = mockProfiles.filter((p) => p.id !== id)
    return mockProfiles
  },
  previewCommand: async (opts) => {
    await new Promise((r) => setTimeout(r, 300)) // simulate the main-process round-trip
    const extra = opts.extraArgs ? ` ${opts.extraArgs}` : ''
    const dir = opts.kind === 'audio' ? MOCK_SETTINGS.audioFolder : MOCK_SETTINGS.videoFolder
    return {
      ok: true,
      command: `yt-dlp.exe -f "bv*+ba/b" -o "${dir}\\%(title)s.%(ext)s"` + `${extra} -- ${opts.url}`
    }
  },
  updateYtdlp: async (channel) => {
    await new Promise((r) => setTimeout(r, 600)) // simulate the self-update run
    return {
      ok: true,
      output: `yt-dlp is already up to date (channel: ${channel}, UI preview mock)`
    }
  },
  // No background updater in the browser preview — hand back an inert unsubscribe.
  onYtdlpAutoUpdateStatus: () => () => {},
  listErrorLog: async () => [],
  clearErrorLog: async () => [],
  listQueue: async () => [],
  saveQueue: async () => {},
  exportBackup: async () => ({
    ok: true,
    path: 'C:\\Users\\you\\Downloads\\aerofetch-backup.json'
  }),
  importBackup: async () => ({ ok: true }),
  onDownloadEvent: () => () => {},
  getSystemTheme: async () => ({
    shouldUseDarkColors: false,
    shouldUseHighContrastColors: false
  }),
  onSystemThemeUpdate: () => () => {},
  openHighContrastSettings: async () => {},
  onExternalUrl: () => () => {},
  onRunWatchedSync: () => () => {},
  // Media-manager sources — a seeded channel so the (Phase H) Library view has
  // demo data in this browser-only preview.
  listSources: async () => [
    {
      id: 'src-demo',
      url: 'https://www.youtube.com/@DevChannel',
      kind: 'channel',
      title: 'DevChannel',
      channel: 'DevChannel',
      addedAt: Date.now() - 86_400_000,
      lastIndexedAt: Date.now() - 3_600_000,
      itemCount: 7
    }
  ],
  indexSource: async (url) => {
    await new Promise((r) => setTimeout(r, 800)) // simulate the index walk
    return {
      ok: true,
      source: {
        id: 'src-demo',
        url,
        kind: 'channel',
        title: 'DevChannel',
        channel: 'DevChannel',
        addedAt: Date.now(),
        lastIndexedAt: Date.now(),
        itemCount: 7
      },
      itemCount: 7
    }
  },
  reindexSource: async () => ({ ok: true, itemCount: 7, newCount: 0 }),
  cancelIndex: async () => {},
  removeSource: async () => [],
  setMediaItemDownloaded: async () => [],
  setSourceWatched: async () => [],
  setSourceProfile: async () => [],
  pruneMediaItems: async () => ({ items: [], deleted: 0 }),
  syncWatchedSources: async () => ({ ok: true, newItems: [] }),
  getScheduledSync: async () => ({ enabled: false }),
  setScheduledSync: async (enabled: boolean) => ({ enabled }),
  listSourceItems: async (sourceId) =>
    Array.from({ length: 7 }, (_, i) => ({
      id: `${sourceId}:vid${i + 1}`,
      sourceId,
      videoId: `vid${i + 1}`,
      title: `Episode ${i + 1}`,
      url: `https://youtube.com/watch?v=vid${i + 1}`,
      playlistTitle: i < 5 ? 'Full Electron Course' : 'Uploads',
      playlistIndex: i < 5 ? i + 1 : i - 4,
      durationLabel: `${10 + i}:0${i}`,
      downloaded: i < 2
    })),
  onIndexProgress: () => () => {},
  runTerminal: async () => ({ ok: true }),
  cancelTerminal: async () => {},
  onTerminalOutput: () => () => {},
  setTaskbarProgress: async () => {},
  mintPoToken: async () => null
}
