import { execAsync, getEnvWithPath } from '../utils/shell-utils';
import log from 'electron-log';
import { BrowserWindow, dialog } from 'electron';
import { spawn } from 'child_process';
import * as path from 'path';
import * as fs from 'fs';
import { createOutputSender } from '../utils/ipc-output-helper';

export interface GitCloneStatus {
  configured: boolean;
  repositoryPath: string | null;
  exists: boolean;
  isValidRepo: boolean;
  isCanvasLmsRepo: boolean;
  remoteUrl: string | null;
  currentBranch: string | null;
  lastCommit: {
    hash: string;
    author: string;
    date: string;
    message: string;
  } | null;
  cloneFolder?: string | null;
  folderName?: string;
}

/**
 * Check if canvas-lms repository is cloned and configured
 */
export async function checkGitCloneStatus(storedPath?: string, folderName = 'dev'): Promise<GitCloneStatus> {
  try {
    if (!storedPath) {
      return {
        configured: false,
        repositoryPath: null,
        exists: false,
        isValidRepo: false,
        isCanvasLmsRepo: false,
        remoteUrl: null,
        currentBranch: null,
        lastCommit: null,
        folderName
      };
    }

    const canvasLmsPath = path.join(storedPath, folderName);

    // Check if directory exists
    if (!fs.existsSync(canvasLmsPath)) {
      return {
        configured: false,
        repositoryPath: canvasLmsPath,
        exists: false,
        isValidRepo: false,
        isCanvasLmsRepo: false,
        remoteUrl: null,
        currentBranch: null,
        lastCommit: null,
        folderName
      };
    }

    // Check if it's a valid git repository
    const gitDir = path.join(canvasLmsPath, '.git');
    if (!fs.existsSync(gitDir)) {
      return {
        configured: false,
        repositoryPath: canvasLmsPath,
        exists: true,
        isValidRepo: false,
        isCanvasLmsRepo: false,
        remoteUrl: null,
        currentBranch: null,
        lastCommit: null,
        folderName
      };
    }

    // Get remote URL
    let remoteUrl: string | null = null;
    let isCanvasLmsRepo = false;
    try {
      const remoteResult = await execAsync('git remote get-url origin', {
        cwd: canvasLmsPath
      });
      remoteUrl = remoteResult.stdout.trim();
      // Check if it's the canvas-lms repository
      isCanvasLmsRepo = remoteUrl.includes('gerrit.instructure.com') && remoteUrl.includes('canvas-lms');
    } catch (error) {
      log.error('Failed to get remote URL:', error);
    }

    // Get current branch
    let currentBranch: string | null = null;
    try {
      const branchResult = await execAsync('git branch --show-current', {
        cwd: canvasLmsPath
      });
      currentBranch = branchResult.stdout.trim();
    } catch (error) {
      log.error('Failed to get current branch:', error);
    }

    // Get last commit info
    let lastCommit = null;
    try {
      const commitResult = await execAsync(
        'git log -1 --pretty=format:"%H%n%an%n%aI%n%s"',
        { cwd: canvasLmsPath }
      );
      const lines = commitResult.stdout.trim().split('\n');
      if (lines.length >= 4) {
        lastCommit = {
          hash: lines[0].substring(0, 7), // Short hash
          author: lines[1],
          date: lines[2],
          message: lines[3]
        };
      }
    } catch (error) {
      log.error('Failed to get last commit:', error);
    }

    return {
      configured: isCanvasLmsRepo,
      repositoryPath: canvasLmsPath,
      exists: true,
      isValidRepo: true,
      isCanvasLmsRepo,
      remoteUrl,
      currentBranch,
      lastCommit,
      folderName
    };
  } catch (error) {
    log.error('Error checking git clone status:', error);
    throw error;
  }
}

/**
 * Select a folder where to clone the repository
 */
export async function selectCloneFolder(window: BrowserWindow | null): Promise<string | null> {
  try {
    const result = await dialog.showOpenDialog(window!, {
      properties: ['openDirectory', 'createDirectory'],
      title: 'Select folder for canvas-lms repository',
      buttonLabel: 'Select Folder'
    });

    if (result.canceled || result.filePaths.length === 0) {
      return null;
    }

    return result.filePaths[0];
  } catch (error) {
    log.error('Error selecting clone folder:', error);
    throw error;
  }
}

/**
 * Clone canvas-lms repository
 */
export async function cloneCanvasLms(
  targetFolder: string,
  window: BrowserWindow | null,
  folderName = 'dev'
): Promise<{ success: boolean; message: string }> {
  const sendOutput = createOutputSender(window, 'git-clone:clone-output');

  try {
    const canvasLmsPath = path.join(targetFolder, folderName);

    // Check if directory already exists
    if (fs.existsSync(canvasLmsPath)) {
      return {
        success: false,
        message: `"${folderName}" directory already exists in the selected folder`
      };
    }

    sendOutput('Cloning canvas-lms repository...');
    sendOutput('This may take several minutes...\n');

    return new Promise((resolve) => {
      const cloneProcess = spawn(
        'git',
        ['clone', 'ssh://gerrit.instructure.com:29418/canvas-lms', folderName],
        {
          cwd: targetFolder,
          env: getEnvWithPath()
        }
      );

      cloneProcess.stdout.on('data', (data) => {
        sendOutput(data.toString());
      });

      cloneProcess.stderr.on('data', (data) => {
        sendOutput(data.toString());
      });

      cloneProcess.on('close', (code) => {
        if (code === 0) {
          sendOutput('\n✓ Repository cloned successfully');
          resolve({
            success: true,
            message: 'canvas-lms repository cloned successfully'
          });
        } else {
          sendOutput(`\n✗ Clone failed with code ${code}`);
          resolve({
            success: false,
            message: `Failed to clone repository (exit code: ${code})`
          });
        }
      });

      cloneProcess.on('error', (error) => {
        sendOutput(`\n✗ Error: ${error.message}`);
        resolve({
          success: false,
          message: error.message
        });
      });
    });
  } catch (error: any) {
    log.error('Error cloning repository:', error);
    return {
      success: false,
      message: error.message || 'Failed to clone repository'
    };
  }
}

/**
 * Reset repository to clean state
 */
export async function resetRepository(
  repositoryPath: string,
  window: BrowserWindow | null
): Promise<{ success: boolean; message: string }> {
  const sendOutput = createOutputSender(window, 'git-clone:reset-output');

  try {
    sendOutput('Resetting repository to clean state...\n');

    // Step 1: git clean -fdx
    sendOutput('Step 1: Cleaning untracked files...');
    const cleanSuccess = await new Promise<boolean>((resolve) => {
      const cleanProcess = spawn('git', ['clean', '-fdx'], {
        cwd: repositoryPath,
        env: getEnvWithPath()
      });

      cleanProcess.stdout.on('data', (data) => {
        sendOutput(data.toString());
      });

      cleanProcess.stderr.on('data', (data) => {
        sendOutput(data.toString());
      });

      cleanProcess.on('close', (code) => {
        if (code === 0) {
          sendOutput('✓ Clean complete\n');
          resolve(true);
        } else {
          sendOutput(`✗ Clean failed with code ${code}\n`);
          resolve(false);
        }
      });

      cleanProcess.on('error', () => {
        resolve(false);
      });
    });

    if (!cleanSuccess) {
      return {
        success: false,
        message: 'Failed to clean repository'
      };
    }

    // Step 2: git checkout master
    sendOutput('Step 2: Checking out master branch...');
    const checkoutSuccess = await new Promise<boolean>((resolve) => {
      const checkoutProcess = spawn('git', ['checkout', 'master'], {
        cwd: repositoryPath,
        env: getEnvWithPath()
      });

      checkoutProcess.stdout.on('data', (data) => {
        sendOutput(data.toString());
      });

      checkoutProcess.stderr.on('data', (data) => {
        sendOutput(data.toString());
      });

      checkoutProcess.on('close', (code) => {
        if (code === 0) {
          sendOutput('✓ Checkout complete\n');
          resolve(true);
        } else {
          sendOutput(`✗ Checkout failed with code ${code}\n`);
          resolve(false);
        }
      });

      checkoutProcess.on('error', () => {
        resolve(false);
      });
    });

    if (!checkoutSuccess) {
      return {
        success: false,
        message: 'Failed to checkout master branch'
      };
    }

    // Step 3: git pull origin master
    sendOutput('Step 3: Pulling latest changes...');
    return new Promise((resolve) => {
      const pullProcess = spawn('git', ['pull', 'origin', 'master'], {
        cwd: repositoryPath,
        env: getEnvWithPath()
      });

      pullProcess.stdout.on('data', (data) => {
        sendOutput(data.toString());
      });

      pullProcess.stderr.on('data', (data) => {
        sendOutput(data.toString());
      });

      pullProcess.on('close', (code) => {
        if (code === 0) {
          sendOutput('\n✓ Repository reset successfully');
          resolve({
            success: true,
            message: 'Repository reset successfully'
          });
        } else {
          sendOutput(`\n✗ Pull failed with code ${code}`);
          resolve({
            success: false,
            message: `Failed to pull latest changes (exit code: ${code})`
          });
        }
      });

      pullProcess.on('error', (error) => {
        sendOutput(`\n✗ Error: ${error.message}`);
        resolve({
          success: false,
          message: error.message
        });
      });
    });
  } catch (error: any) {
    log.error('Error resetting repository:', error);
    return {
      success: false,
      message: error.message || 'Failed to reset repository'
    };
  }
}
