import { app, shell, BrowserWindow, ipcMain, dialog } from 'electron'
import { join } from 'path'
import * as gitService from './gitService'
import * as authService from './authService'
import * as aiService from './aiService'
import { toggleAutoSync } from './autoSync'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset'

function createWindow(): void {
  const mainWindow = new BrowserWindow({
    width: 1100,
    height: 800,
    show: false,
    autoHideMenuBar: true,
    title: 'GIT ELECTRON',
    ...(process.platform === 'linux' ? { icon } : {}),
    webPreferences: {
      preload: join(__dirname, '../preload/index.js'),
      sandbox: false
    }
  })

  const sessionId = mainWindow.webContents.id

  // Initialize auth session for this window
  authService.initSession(sessionId)

  mainWindow.on('ready-to-show', () => {
    mainWindow.show()
  })

  mainWindow.on('closed', () => {
    // Clean up memory using the captured sessionId
    authService.cleanupSession(sessionId)
    gitService.cleanupGitSession(sessionId)
  })

  mainWindow.webContents.setWindowOpenHandler((details) => {
    shell.openExternal(details.url)
    return { action: 'deny' }
  })

  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
  } else {
    mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
  }
}

const gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
  app.quit()
  process.exit(0)
}

let initialRepo: string | null = null
const cwdIndex = process.argv.indexOf('--cwd')
if (cwdIndex !== -1 && process.argv.length > cwdIndex + 1) {
  initialRepo = process.argv[cwdIndex + 1]
}

app.on('second-instance', (_event, commandLine, workingDirectory) => {
  const windows = BrowserWindow.getAllWindows()
  if (windows.length > 0) {
    if (windows[0].isMinimized()) windows[0].restore()
    windows[0].focus()

    const idx = commandLine.indexOf('--cwd')
    let repoPath: string | null = null
    if (idx !== -1 && commandLine.length > idx + 1) {
      repoPath = commandLine[idx + 1]
    } else if (workingDirectory) {
      repoPath = workingDirectory
    }

    if (repoPath) {
      windows[0].webContents.send('set-cli-repo', repoPath)
    }
  }
})

if (process.defaultApp) {
  if (process.argv.length >= 2) {
    app.setAsDefaultProtocolClient('gitelectron', process.execPath, [
      require('path').resolve(process.argv[1])
    ])
  }
} else {
  app.setAsDefaultProtocolClient('gitelectron')
}

app.whenReady().then(async () => {
  electronApp.setAppUserModelId('com.electron')

  await authService.loadAccounts()

  app.on('browser-window-created', (_, window) => {
    optimizer.watchWindowShortcuts(window)
  })

  ipcMain.on('ping', () => console.log('pong'))

  // NEW: Session & Account Management
  ipcMain.handle('new-window', () => {
    createWindow()
  })

  ipcMain.handle('get-accounts', async (event) => {
    return await authService.getAccounts(event.sender.id)
  })

  ipcMain.handle('switch-account', async (event, accountId: string) => {
    return await authService.switchAccount(event.sender.id, accountId)
  })

  ipcMain.handle('remove-account', async (_, accountId: string) => {
    return await authService.removeAccount(accountId)
  })

  // Git IPC Handlers
  ipcMain.handle('get-cli-repo', () => {
    return initialRepo
  })

  ipcMain.handle('select-directory', async (event) => {
    const sessionId = event.sender.id
    const result = await dialog.showOpenDialog({
      properties: ['openDirectory']
    })
    if (result.canceled || result.filePaths.length === 0) {
      return null
    }
    const path = result.filePaths[0]
    const isRepo = await gitService.isGitRepo(path)
    if (isRepo) {
      gitService.initGit(sessionId, path)
    }
    return { path, isRepo }
  })

  ipcMain.handle('set-repo-path', async (event, path: string) => {
    const sessionId = event.sender.id
    const isRepo = await gitService.isGitRepo(path)
    if (isRepo) {
      gitService.initGit(sessionId, path)
    }
    return { path, isRepo }
  })

  ipcMain.handle('init-repo', async (event, path: string) => {
    return await gitService.initializeRepo(event.sender.id, path)
  })

  ipcMain.handle('get-status', async (event) => {
    return await gitService.getStatus(event.sender.id)
  })

  ipcMain.handle('stage-files', async (event, files: string[]) => {
    return await gitService.stageFiles(event.sender.id, files)
  })

  ipcMain.handle('unstage-files', async (event, files: string[]) => {
    return await gitService.unstageFiles(event.sender.id, files)
  })

  ipcMain.handle('commit-changes', async (event, message: string) => {
    return await gitService.commitChanges(event.sender.id, message)
  })

  ipcMain.handle('push-to-remote', async (event, remote: string, branch: string) => {
    return await gitService.pushToRemote(event.sender.id, remote, branch)
  })

  ipcMain.handle('pull-from-remote', async (event, remote: string, branch: string) => {
    return await gitService.pullFromRemote(event.sender.id, remote, branch)
  })

  ipcMain.handle('reset-to-remote', async (event, remote: string, branch: string) => {
    return await gitService.resetToRemote(event.sender.id, remote, branch)
  })

  ipcMain.handle('fetch-remote', async (event) => {
    return await gitService.fetchRemote(event.sender.id)
  })

  ipcMain.handle('get-branches', async (event) => {
    return await gitService.getBranches(event.sender.id)
  })

  ipcMain.handle('checkout-branch', async (event, branch: string) => {
    return await gitService.checkoutBranch(event.sender.id, branch)
  })

  ipcMain.handle('create-branch', async (event, branch: string, baseBranch?: string) => {
    return await gitService.createBranch(event.sender.id, branch, baseBranch)
  })

  ipcMain.handle('get-commit-history', async (event) => {
    return await gitService.getCommitHistory(event.sender.id)
  })

  ipcMain.handle('get-auth-status', async (event) => {
    return await authService.getAuthStatus(event.sender.id)
  })

  ipcMain.handle('start-device-flow', async (event) => {
    const data = await authService.startDeviceFlow(event.sender.id)
    shell.openExternal(data.verification_uri_complete)
    return data
  })

  ipcMain.handle('poll-device-flow', async (event, deviceCode: string, interval: number) => {
    return await authService.pollDeviceFlow(event.sender.id, deviceCode, interval)
  })

  ipcMain.handle('logout-github', async (event) => {
    return await authService.logout(event.sender.id)
  })

  ipcMain.handle('verify-push-permission', async (event, remoteUrl: string) => {
    return await authService.verifyRepositoryPermission(event.sender.id, remoteUrl)
  })

  ipcMain.handle('get-remotes', async (event) => {
    return await gitService.getRemotes(event.sender.id)
  })

  ipcMain.handle('get-file-diff', async (event, file: string, staged: boolean) => {
    return await gitService.getFileDiff(event.sender.id, file, staged)
  })

  ipcMain.handle('get-git-config', async (event, key: string, global: boolean) => {
    return await gitService.getGitConfig(event.sender.id, key, global)
  })

  ipcMain.handle('set-git-config', async (event, key: string, value: string, global: boolean) => {
    return await gitService.setGitConfig(event.sender.id, key, value, global)
  })

  ipcMain.handle('read-file', async (event, file: string) => {
    return await gitService.readFile(event.sender.id, file)
  })

  ipcMain.handle('write-file', async (event, file: string, content: string) => {
    return await gitService.writeFile(event.sender.id, file, content)
  })

  ipcMain.handle('get-user-repositories', async (event) => {
    return await authService.getUserRepositories(event.sender.id)
  })

  ipcMain.handle(
    'create-github-repository',
    async (
      event,
      name: string,
      description: string,
      isPrivate: boolean,
      autoInit: boolean,
      gitignoreTemplate: string,
      licenseTemplate: string
    ) => {
      return await authService.createGitHubRepository(
        event.sender.id,
        name,
        description,
        isPrivate,
        autoInit,
        gitignoreTemplate,
        licenseTemplate
      )
    }
  )

  ipcMain.handle('add-remote', async (event, name: string, url: string) => {
    return await gitService.addRemote(event.sender.id, name, url)
  })

  ipcMain.handle('push-all-branches', async (event, remote: string) => {
    return await gitService.pushAllBranches(event.sender.id, remote)
  })

  ipcMain.handle('open-external', async (_, url: string) => {
    await shell.openExternal(url)
  })

  ipcMain.handle(
    'compare-external-file',
    async (event, sourcePath: string, repoRelativePath: string) => {
      return await gitService.compareExternalFile(event.sender.id, sourcePath, repoRelativePath)
    }
  )

  ipcMain.handle('copy-external-files', async (event, files: string[], destinationDir: string) => {
    return await gitService.copyExternalFiles(event.sender.id, files, destinationDir)
  })

  ipcMain.handle('get-collaborators', async (event, remoteUrl: string) => {
    return await authService.getCollaborators(event.sender.id, remoteUrl)
  })

  ipcMain.handle('add-collaborator', async (event, remoteUrl: string, username: string) => {
    return await authService.addCollaborator(event.sender.id, remoteUrl, username)
  })

  ipcMain.handle(
    'remove-collaborator',
    async (event, remoteUrl: string, usernameOrId: string, isInvitation: boolean) => {
      return await authService.removeCollaborator(
        event.sender.id,
        remoteUrl,
        usernameOrId,
        isInvitation
      )
    }
  )

  ipcMain.handle('search-github-user', async (event, username: string) => {
    return await authService.searchGitHubUser(event.sender.id, username)
  })

  // ---------------------------------------------------------
  // UNIVERSAL PUSH (PUSH ANYTHING) IPC HANDLERS
  // ---------------------------------------------------------

  ipcMain.handle('select-universal-files', async (_event, isDirectory: boolean) => {
    const properties: any[] = isDirectory
      ? ['openDirectory', 'multiSelections']
      : ['openFile', 'multiSelections']
    const result = await dialog.showOpenDialog({ properties })
    return result.canceled ? null : result.filePaths
  })

  ipcMain.handle('get-repository-branches', async (event, owner: string, repo: string) => {
    return await authService.getRepositoryBranches(event.sender.id, owner, repo)
  })

  ipcMain.handle(
    'setup-universal-workspace',
    async (event, remoteUrl: string, branch: string, baseBranch: string | null, dest: string) => {
      return await gitService.setupUniversalWorkspace(
        event.sender.id,
        remoteUrl,
        branch,
        baseBranch,
        dest
      )
    }
  )

  ipcMain.handle(
    'check-universal-collisions',
    async (_event, workspacePath: string, sourceFiles: string[], dest: string) => {
      return await gitService.checkUniversalCollisions(workspacePath, sourceFiles, dest)
    }
  )

  ipcMain.handle('get-universal-diff', async (_event, workspacePath: string, file: string) => {
    return await gitService.getUniversalDiff(workspacePath, file)
  })

  ipcMain.handle(
    'commit-universal-workspace',
    async (_event, workspacePath: string, msg: string, branch: string) => {
      return await gitService.commitUniversalWorkspace(workspacePath, msg, branch)
    }
  )

  ipcMain.handle('cleanup-universal-workspace', async (_event, workspacePath: string) => {
    return await gitService.cleanupUniversalWorkspace(workspacePath)
  })

  ipcMain.handle(
    'ask-ai',
    async (
      event,
      provider: 'gemini' | 'deepseek',
      apiKey: string,
      errorMsg: string,
      gitStatus: any,
      repoPath: string
    ) => {
      const githubToken = authService.getToken(event.sender.id) || undefined
      return await aiService.analyzeGitError(
        provider,
        apiKey,
        errorMsg,
        gitStatus,
        repoPath,
        githubToken
      )
    }
  )

  ipcMain.handle('execute-raw-git', async (event, args: string[]) => {
    return await gitService.executeRawCommand(event.sender.id, args)
  })

  ipcMain.on('toggle-auto-sync', (event, repoPath: string, enabled: boolean) => {
    toggleAutoSync(event.sender.id, repoPath, enabled, (msg) => {
      event.sender.send('auto-sync-log', msg)
    })
  })

  ipcMain.handle('get-app-version', () => {
    return app.getVersion()
  })

  ipcMain.handle('check-updates', async () => {
    try {
      const https = require('https')
      return new Promise((resolve) => {
        https
          .get('https://registry.npmjs.org/gitelectron/latest', (res: any) => {
            let data = ''
            res.on('data', (chunk: any) => {
              data += chunk
            })
            res.on('end', () => {
              try {
                const json = JSON.parse(data)
                resolve(json.version || null)
              } catch (e) {
                resolve(null)
              }
            })
          })
          .on('error', () => resolve(null))
      })
    } catch (e) {
      return null
    }
  })

  ipcMain.handle('install-update', async () => {
    return new Promise((resolve, reject) => {
      const { exec } = require('child_process')
      exec('npm i -g gitelectron@latest gitquickpush-cli@latest', (error: any) => {
        if (error) {
          reject(error.message)
        } else {
          app.relaunch()
          app.exit(0)
          resolve(true)
        }
      })
    })
  })

  createWindow()

  app.on('activate', function () {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})
