import { app, BrowserWindow, ipcMain } from 'electron';
import log from 'electron-log';
import { createTray, destroyTray, updateTrayIcon } from './tray';
import { registerShortcuts, unregisterAllShortcuts } from './shortcuts';
import { initializeUpdater } from './updater';
import { settingsStore, SetupWizardState } from './store';
import { SETUP_WIZARD_STEPS } from './setup-wizard/steps';
import { showSetupWizardWindow } from './setup-wizard-window';
import { showCareerWizardWindow } from './career-wizard-window';
import { showActionsWindow, getActionsWindow } from './actions-window';
import { actionsStore, ActionEntry } from './actions-store';
import { checkDockerStatus, checkHomebrewStatus } from './system-manager';
import { checkFrpcStatus } from './services/frpc-manager';
import { checkGitConfigStatus } from './services/git-manager';
import { checkSshKeyStatus } from './services/ssh-manager';
import { checkArtifactoryStatus } from './services/artifactory-manager';
import { checkInstCliStatus } from './services/inst-cli-manager';
import { createSetupWizardCache, type SetupWizardCacheKey, CacheManager } from './services/cache-manager';
import { registerSettingsHandlers } from './ipc-handlers/settings-handlers';
import { registerSystemHandlers } from './ipc-handlers/system-handlers';
import { registerToolHandlers } from './ipc-handlers/tool-handlers';
import { registerSetupWizardHandlers } from './ipc-handlers/setup-wizard-handlers';
import { registerCareerWizardHandlers, type CareerWizardCacheKey } from './ipc-handlers/career-wizard-handlers';
import { registerLearnerHubHandlers, type LearnerHubCacheKey } from './ipc-handlers/learner-hub-handlers';
import { registerBackupRestoreHandlers } from './ipc-handlers/backup-restore-handlers';

// Set app name
app.setName('Instructure Agent');

// Configure logging
log.transports.file.level = 'info';
log.transports.console.level = 'debug';

// Set log file path to use "Instructure Agent" folder
const path = require('path');
const os = require('os');
log.transports.file.resolvePathFn = () => {
  return path.join(os.homedir(), 'Library', 'Logs', 'Instructure Agent', 'main.log');
};

// In-memory cache for onboarding data
// Create setup wizard cache with 5-minute TTL
const setupWizardCache = createSetupWizardCache(5 * 60 * 1000);

// Create career wizard cache with 5-minute TTL
const careerWizardCache = new CacheManager<CareerWizardCacheKey, any>({
  ttl: 5 * 60 * 1000,
  maxSize: 50
});

// Create learner hub cache with 5-minute TTL
const learnerHubCache = new CacheManager<LearnerHubCacheKey, any>({
  ttl: 5 * 60 * 1000,
  maxSize: 50
});

// Periodically clean up expired cache entries (every 10 minutes)
setInterval(() => {
  setupWizardCache.invalidateExpired();
  careerWizardCache.invalidateExpired();
  learnerHubCache.invalidateExpired();
}, 10 * 60 * 1000);

// Register protocol handler
if (process.defaultApp) {
  if (process.argv.length >= 2) {
    app.setAsDefaultProtocolClient('instructure', process.execPath, [process.argv[1]]);
  }
} else {
  app.setAsDefaultProtocolClient('instructure');
}

// Handle protocol URLs
function handleProtocolUrl(url: string): void {
  log.info(`Protocol URL received: ${url}`);

  // Add action to store
  const action = actionsStore.add(url);

  // Notify actions window if it's open
  const actionsWindow = getActionsWindow();
  if (actionsWindow) {
    actionsWindow.webContents.send('action:added', action);
  }

  // TODO: Process the URL and execute commands
  // For now, just log it
  actionsStore.addLog(action.id, `Received URL: ${url}`);
  actionsStore.update(action.id, { status: 'completed' });
}

// Handle single instance lock
const gotTheLock = app.requestSingleInstanceLock();

if (!gotTheLock) {
  log.warn('Another instance is already running');
  app.quit();
} else {
  app.on('second-instance', (_event, commandLine) => {
    log.info('Second instance attempted to start');

    // Handle protocol URL from second instance
    const url = commandLine.find(arg => arg.startsWith('instructure://'));
    if (url) {
      handleProtocolUrl(url);
    }
  });
}

// Handle open action
function handleOpen(): void {
  log.info('Open action triggered');

  // Show appropriate window based on onboarding status
  const onboardingState = settingsStore.get('onboarding');
  if (onboardingState.completed) {
    showActionsWindow();
  } else {
    showSetupWizardWindow();
  }
}

// Pre-fetch all onboarding data for caching
async function prefetchOnboardingData(): Promise<void> {
  log.info('Pre-fetching onboarding data...');

  try {
    // Fetch all step data in parallel
    const [
      homebrewStatus,
      dockerStatus,
      gitConfigStatus,
      sshKeyStatus,
      artifactoryStatus,
      instCliStatus,
      frpcStatus
    ] = await Promise.all([
      checkHomebrewStatus().catch(err => {
        log.error('Failed to fetch Homebrew status:', err);
        return null;
      }),
      checkDockerStatus().catch(err => {
        log.error('Failed to fetch Docker status:', err);
        return null;
      }),
      checkGitConfigStatus().catch(err => {
        log.error('Failed to fetch Git config status:', err);
        return null;
      }),
      checkSshKeyStatus().catch(err => {
        log.error('Failed to fetch SSH key status:', err);
        return null;
      }),
      checkArtifactoryStatus().catch(err => {
        log.error('Failed to fetch Artifactory status:', err);
        return null;
      }),
      checkInstCliStatus().catch(err => {
        log.error('Failed to fetch inst-cli status:', err);
        return null;
      }),
      checkFrpcStatus().catch(err => {
        log.error('Failed to fetch FRPC status:', err);
        return null;
      })
    ]);

    // Update cache with new API
    if (homebrewStatus) setupWizardCache.set('homebrewStatus', homebrewStatus);
    if (dockerStatus) setupWizardCache.set('dockerStatus', dockerStatus);
    if (gitConfigStatus) setupWizardCache.set('gitConfigStatus', gitConfigStatus);
    if (sshKeyStatus) setupWizardCache.set('sshKeyStatus', sshKeyStatus);
    if (artifactoryStatus) setupWizardCache.set('artifactoryStatus', artifactoryStatus);
    if (instCliStatus) setupWizardCache.set('instCliStatus', instCliStatus);
    if (frpcStatus) setupWizardCache.set('frpcStatus', frpcStatus);

    log.info('Onboarding data pre-fetched and cached');
  } catch (error) {
    log.error('Error during onboarding data pre-fetch:', error);
  }
}

/**
 * Check all onboarding steps and update tray icon based on validation
 */
export async function checkStepsAndUpdateTrayIcon(): Promise<void> {
  try {
    log.info('Checking all onboarding steps for tray icon update...');

    // Validate all steps
    const validationResults = await Promise.all(
      SETUP_WIZARD_STEPS.map(async (step) => {
        try {
          const result = await step.validate();
          return { stepId: step.id, isComplete: result.isComplete };
        } catch (error) {
          log.error(`Failed to validate step ${step.id}:`, error);
          return { stepId: step.id, isComplete: false };
        }
      })
    );

    // Check if all steps are complete
    const allStepsPassing = validationResults.every(result => result.isComplete);

    log.info(`Steps validation complete. All passing: ${allStepsPassing}`, {
      total: validationResults.length,
      passing: validationResults.filter(r => r.isComplete).length
    });

    // Update tray icon
    updateTrayIcon(allStepsPassing);
  } catch (error) {
    log.error('Error checking steps for tray icon update:', error);
  }
}

// IPC handlers registration
function setupIPCHandlers(): void {
  // Register all IPC handlers using specialized handler modules
  registerSettingsHandlers();
  registerSystemHandlers(setupWizardCache);
  registerToolHandlers();
  registerSetupWizardHandlers(setupWizardCache);
  registerCareerWizardHandlers(careerWizardCache);
  registerLearnerHubHandlers(learnerHubCache);
  registerBackupRestoreHandlers();

  log.info('All IPC handlers registered');
}

// App lifecycle handlers
app.on('ready', async () => {
  log.info('App is ready');

  // Hide dock icon on macOS to run as background agent
  if (process.platform === 'darwin') {
    app.dock.hide();
    log.info('Dock icon hidden');
  }

  // Initialize components
  setupIPCHandlers();
  await createTray(handleOpen);
  registerShortcuts(handleOpen);
  initializeUpdater();

  // Pre-fetch onboarding data in background
  prefetchOnboardingData();

  // Check all steps and update tray icon
  setTimeout(() => {
    checkStepsAndUpdateTrayIcon();
  }, 2000); // Wait 2 seconds for data to be fetched

  log.info('Instructure Agent started successfully');
});

app.on('window-all-closed', (event: Event) => {
  // Prevent app from quitting when all windows are closed
  // This is a background agent, so it should keep running
  event.preventDefault();
  log.info('All windows closed, but app continues running');
});

app.on('before-quit', () => {
  log.info('App is quitting');
  unregisterAllShortcuts();
  destroyTray();
});

app.on('will-quit', () => {
  log.info('App will quit');
});

app.on('activate', () => {
  // On macOS, bring windows to foreground when dock icon is clicked
  log.info('App activated');

  // Import window getters
  const { getSetupWizardWindow } = require('./setup-wizard-window');
  const { getActionsWindow } = require('./actions-window');

  // Check for any open windows and bring them to the foreground
  const setupWizardWindow = getSetupWizardWindow();
  const actionsWindow = getActionsWindow();

  if (setupWizardWindow) {
    setupWizardWindow.show();
    setupWizardWindow.focus();
    log.info('Brought setup wizard window to foreground');
  } else if (actionsWindow) {
    actionsWindow.show();
    actionsWindow.focus();
    log.info('Brought actions window to foreground');
  }
});

// Handle protocol URLs on macOS
app.on('open-url', (event, url) => {
  event.preventDefault();
  log.info(`open-url event: ${url}`);
  handleProtocolUrl(url);
});

// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
  log.error('Uncaught exception:', error);
});

process.on('unhandledRejection', (reason, promise) => {
  log.error('Unhandled rejection at:', promise, 'reason:', reason);
});
