import { ipcMain, BrowserWindow, dialog } from 'electron';
import log from 'electron-log';
import { settingsStore, SetupWizardState } from '../store';
import { SETUP_WIZARD_STEPS } from '../setup-wizard/steps';
import { checkStepsAndUpdateTrayIcon } from '../index';
import { CacheManager, type SetupWizardCacheKey } from '../services/cache-manager';
import {
  checkArtifactoryStatus,
  setupArtifactory,
  ArtifactorySetupOptions
} from '../services/artifactory-manager';
import {
  checkInstCliStatus,
  buildInstCliImage
} from '../services/inst-cli-manager';
import {
  checkGitConfigStatus,
  updateGitConfig,
  installGit,
  GitConfigOptions
} from '../services/git-manager';
import {
  checkSshKeyStatus,
  generateSshKeys,
  SshKeyGenerateOptions,
  readPublicKey,
  copyAndSetupSshKeys,
  updateSshConfig,
  updateGerritSshConfig,
  testGerritSshConnection,
  getGerritUsername
} from '../services/ssh-manager';

/**
 * Register setup wizard IPC handlers
 */
export function registerSetupWizardHandlers(cache: CacheManager<SetupWizardCacheKey, any>): void {
  // Onboarding state
  ipcMain.handle('onboarding:get-state', async () => {
    return settingsStore.get('onboarding');
  });

  ipcMain.handle('onboarding:set-state', async (_event, state: SetupWizardState) => {
    settingsStore.set('onboarding', state);
  });

  // Onboarding steps
  ipcMain.handle('onboarding:get-steps', async () => {
    return SETUP_WIZARD_STEPS.map(step => ({
      id: step.id,
      title: step.title,
      description: step.description,
      componentName: step.componentName,
      order: step.order,
      required: step.required,
      icon: step.icon
    }));
  });

  ipcMain.handle('onboarding:validate-step', async (_event, stepId: string) => {
    const step = SETUP_WIZARD_STEPS.find(s => s.id === stepId);
    if (!step) throw new Error(`Step not found: ${stepId}`);
    return await step.validate();
  });

  ipcMain.handle('onboarding:update-tray-icon', async () => {
    try {
      await checkStepsAndUpdateTrayIcon();
    } catch (error) {
      log.error('Error updating tray icon:', error);
      throw error;
    }
  });

  // Artifactory
  ipcMain.handle('artifactory:get-status', async (_event, forceRefresh = false) => {
    try {
      if (!forceRefresh && cache.get('artifactoryStatus')) {
        log.info('Returning cached Artifactory status');
        return cache.get('artifactoryStatus');
      }

      const status = await checkArtifactoryStatus();
      cache.set('artifactoryStatus', status);
      return status;
    } catch (error) {
      log.error('Error checking Artifactory status:', error);
      throw error;
    }
  });

  ipcMain.handle('artifactory:setup', async (_event, options: ArtifactorySetupOptions) => {
    try {
      return await setupArtifactory(options);
    } catch (error) {
      log.error('Error setting up Artifactory:', error);
      throw error;
    }
  });

  // Inst CLI
  ipcMain.handle('inst-cli:get-status', async (_event, forceRefresh = false) => {
    try {
      if (!forceRefresh && cache.get('instCliStatus')) {
        log.info('Returning cached inst-cli status');
        return cache.get('instCliStatus');
      }

      const status = await checkInstCliStatus();
      cache.set('instCliStatus', status);
      return status;
    } catch (error) {
      log.error('Error checking inst-cli status:', error);
      throw error;
    }
  });

  ipcMain.handle('inst-cli:build', async (event) => {
    try {
      const window = BrowserWindow.fromWebContents(event.sender);
      if (!window) {
        throw new Error('Could not find window');
      }
      return await buildInstCliImage(window);
    } catch (error) {
      log.error('Error building inst-cli image:', error);
      throw error;
    }
  });

  // Git Config
  ipcMain.handle('git:get-status', async (_event, forceRefresh = false) => {
    try {
      if (!forceRefresh && cache.get('gitConfigStatus')) {
        log.info('Returning cached Git config status');
        return cache.get('gitConfigStatus');
      }

      const status = await checkGitConfigStatus();
      cache.set('gitConfigStatus', status);
      return status;
    } catch (error) {
      log.error('Error checking Git config status:', error);
      throw error;
    }
  });

  ipcMain.handle('git:update-config', async (_event, options: GitConfigOptions) => {
    try {
      return await updateGitConfig(options);
    } catch (error) {
      log.error('Error updating Git config:', error);
      throw error;
    }
  });

  ipcMain.handle('git:install', async (event) => {
    try {
      const window = BrowserWindow.fromWebContents(event.sender);
      return await installGit(window);
    } catch (error) {
      log.error('Error installing Git:', error);
      throw error;
    }
  });

  // SSH Keys
  ipcMain.handle('ssh:get-status', async (_event, publicKeyPath?: string, forceRefresh = false) => {
    try {
      if (!publicKeyPath && !forceRefresh && cache.get('sshKeyStatus')) {
        log.info('Returning cached SSH key status');
        return cache.get('sshKeyStatus');
      }

      const status = await checkSshKeyStatus(publicKeyPath);

      if (!publicKeyPath) {
        cache.set('sshKeyStatus', status);
      }

      return status;
    } catch (error) {
      log.error('Error checking SSH key status:', error);
      throw error;
    }
  });

  ipcMain.handle('ssh:generate-keys', async (_event, options: SshKeyGenerateOptions) => {
    try {
      return await generateSshKeys(options);
    } catch (error) {
      log.error('Error generating SSH keys:', error);
      throw error;
    }
  });

  ipcMain.handle('ssh:select-public-key', async () => {
    try {
      const result = await dialog.showOpenDialog({
        title: 'Select SSH Public Key',
        defaultPath: require('os').homedir() + '/.ssh',
        properties: ['openFile'],
        filters: [
          { name: 'SSH Public Keys', extensions: ['pub'] },
          { name: 'All Files', extensions: ['*'] }
        ]
      });

      if (!result.canceled && result.filePaths.length > 0) {
        const selectedPublicKeyPath = result.filePaths[0];

        // Copy keys to ~/.ssh and set proper permissions
        const setupResult = await copyAndSetupSshKeys(selectedPublicKeyPath);

        if (!setupResult.success) {
          log.error('Failed to setup SSH keys:', setupResult.message);
          throw new Error(setupResult.message);
        }

        log.info('SSH keys setup completed:', setupResult);

        // Return the path to the key in ~/.ssh (which may be the same as selected if already there)
        return {
          filePath: setupResult.publicKeyPath,
          copied: setupResult.copied,
          message: setupResult.message
        };
      }
      return null;
    } catch (error) {
      log.error('Error selecting public key:', error);
      throw error;
    }
  });

  ipcMain.handle('ssh:update-config', async (_event, privateKeyPath: string) => {
    try {
      const result = await updateSshConfig(privateKeyPath);

      if (!result.success) {
        log.error('Failed to update SSH config:', result.message);
        throw new Error(result.message);
      }

      log.info('SSH config updated successfully');
      return result;
    } catch (error) {
      log.error('Error updating SSH config:', error);
      throw error;
    }
  });

  ipcMain.handle('ssh:get-gerrit-username', async () => {
    try {
      const username = await getGerritUsername();
      return username;
    } catch (error) {
      log.error('Error getting Gerrit username:', error);
      return null;
    }
  });

  ipcMain.handle('ssh:update-gerrit-config', async (_event, privateKeyPath: string, username: string) => {
    try {
      const result = await updateGerritSshConfig(privateKeyPath, username);

      if (!result.success) {
        log.error('Failed to update Gerrit SSH config:', result.message);
        throw new Error(result.message);
      }

      log.info('Gerrit SSH config updated successfully');
      return result;
    } catch (error) {
      log.error('Error updating Gerrit SSH config:', error);
      throw error;
    }
  });

  ipcMain.handle('ssh:test-gerrit', async (_event, privateKeyPath: string) => {
    try {
      const result = await testGerritSshConnection(privateKeyPath);
      return {
        success: result.connected,
        message: result.message
      };
    } catch (error: any) {
      log.error('Error testing Gerrit connection:', error);
      return {
        success: false,
        message: error.message || 'Failed to test Gerrit connection'
      };
    }
  });

  ipcMain.handle('ssh:read-public-key', async (_event, publicKeyPath: string) => {
    try {
      return await readPublicKey(publicKeyPath);
    } catch (error) {
      log.error('Error reading public key:', error);
      throw error;
    }
  });

  log.info('Setup wizard handlers registered');
}
