import { promises as fs } from 'fs';
import { homedir } from 'os';
import { join } from 'path';
import log from 'electron-log';
import * as yaml from 'js-yaml';

export interface InstConfigStatus {
  exists: boolean;
  content: string | null;
  path: string;
  actualFileContent?: string | null;
}

const INST_CONFIG_PATH = join(homedir(), '.inst-cli', 'inst.yml');

const DEFAULT_CONFIG_TEMPLATE = `---
inst:
  base_code_directory: {{BASE_DIR}}
  git_server_url: ssh://gerrit.instructure.com:29418
  inst_domain: inseng.test
  canvas-lms:
    source: {{CANVAS_SOURCE}}
    plugins:
    - multiple_root_accounts
    - demo_site
    - canvas_geoip
    - uuid_provisioner
    - instructure_misc_plugin
    - QTIMigrationTool:
        git_url: https://github.com/instructure
        clone_to: vendor
    environment:
      CANVAS_LMS_ADMIN_EMAIL: admin@fake.com
      CANVAS_LMS_ADMIN_PASSWORD: fakepassword
      CANVAS_LMS_ACCOUNT_NAME: Fake Academy
      CANVAS_LMS_STATS_COLLECTION: opt_out

`;

/**
 * Check the status of inst.yml configuration file
 */
export async function checkInstConfigStatus(cloneFolder?: string, folderName = 'dev'): Promise<InstConfigStatus> {
  try {
    let content: string | null = null;
    let actualFileContent: string | null = null;
    let exists = false;

    try {
      actualFileContent = await fs.readFile(INST_CONFIG_PATH, 'utf-8');
      exists = true;
      content = actualFileContent;

      // If we have a clone folder, replace the paths in the displayed content
      if (cloneFolder) {
        content = replacePaths(actualFileContent, cloneFolder, folderName);
      }
    } catch (error: any) {
      if (error.code === 'ENOENT') {
        log.info('inst.yml does not exist');
        // Generate default content if clone folder is provided
        if (cloneFolder) {
          content = DEFAULT_CONFIG_TEMPLATE
            .replace('{{BASE_DIR}}', cloneFolder)
            .replace('{{CANVAS_SOURCE}}', join(cloneFolder, folderName));
        } else {
          content = DEFAULT_CONFIG_TEMPLATE
            .replace('{{BASE_DIR}}', '$REPLACE_WITH_GIT_CLONE_FOLDER')
            .replace('{{CANVAS_SOURCE}}', '$REPLACE_WITH_GIT_CLONE_FOLDER/dev');
        }
      } else {
        throw error;
      }
    }

    return {
      exists,
      content,
      actualFileContent,
      path: INST_CONFIG_PATH
    };
  } catch (error) {
    log.error('Error checking inst.yml status:', error);
    throw error;
  }
}

/**
 * Replace base_code_directory and canvas-lms source paths
 */
function replacePaths(content: string, cloneFolder: string, folderName = 'dev'): string {
  const lines = content.split('\n');
  let inCanvasSection = false;
  let canvasIndent = '  ';

  const updatedLines = lines.map((line, index) => {
    const trimmed = line.trim();

    // Replace base_code_directory (commented or not)
    if (trimmed.startsWith('base_code_directory:') || trimmed.startsWith('# base_code_directory:')) {
      const indent = line.match(/^\s*/)?.[0] || '  ';
      return `${indent}base_code_directory: ${cloneFolder}`;
    }

    // Detect commented canvas-lms section
    if (trimmed === '# canvas-lms:' || trimmed === 'canvas-lms:') {
      inCanvasSection = true;
      // Get the base indent of canvas-lms line (without the # and spaces after #)
      const match = line.match(/^(\s*)#?\s*canvas-lms:/);
      canvasIndent = match ? match[1] : '  ';
      return `${canvasIndent}canvas-lms:`;
    }

    // If we're in canvas section and find source line (commented or not)
    if (inCanvasSection && (trimmed.startsWith('source:') || trimmed.startsWith('# source:') || trimmed.startsWith('#   source:'))) {
      // Add 2 spaces for proper YAML indentation under canvas-lms
      const sourceIndent = canvasIndent + '  ';
      inCanvasSection = false; // Reset after finding source
      return `${sourceIndent}source: ${join(cloneFolder, folderName)}`;
    }

    // Reset canvas section flag if we hit a non-commented, non-indented line
    if (inCanvasSection && trimmed && !trimmed.startsWith('#') && !line.startsWith(' ') && !line.startsWith('\t')) {
      inCanvasSection = false;
    }

    return line;
  });

  return updatedLines.join('\n');
}

/**
 * Validate inst.yml configuration content
 */
function validateConfigContent(content: string): { valid: boolean; message: string } {
  const lines = content.split('\n');
  let hasBaseCodeDirectory = false;
  let hasCanvasSource = false;

  for (const line of lines) {
    const trimmed = line.trim();

    // Check for base_code_directory (not commented)
    if (trimmed.startsWith('base_code_directory:') && !trimmed.startsWith('#')) {
      const value = trimmed.substring('base_code_directory:'.length).trim();
      if (value && value !== '$REPLACE_WITH_GIT_CLONE_FOLDER') {
        hasBaseCodeDirectory = true;
      }
    }

    // Check for canvas-lms source (not commented)
    if (trimmed.startsWith('source:') && !trimmed.startsWith('#')) {
      const value = trimmed.substring('source:'.length).trim();
      if (value && value !== '$REPLACE_WITH_GIT_CLONE_FOLDER/dev' && !value.startsWith('<')) {
        hasCanvasSource = true;
      }
    }
  }

  if (!hasBaseCodeDirectory) {
    return {
      valid: false,
      message: 'Configuration must include a valid base_code_directory'
    };
  }

  if (!hasCanvasSource) {
    return {
      valid: false,
      message: 'Configuration must include a valid canvas-lms source path'
    };
  }

  return {
    valid: true,
    message: 'Configuration is valid'
  };
}

/**
 * Save inst.yml configuration file
 */
export async function saveInstConfig(content: string): Promise<{ success: boolean; message: string }> {
  try {
    // Validate content first
    const validation = validateConfigContent(content);
    if (!validation.valid) {
      return {
        success: false,
        message: validation.message
      };
    }

    // Ensure directory exists
    const dir = join(homedir(), '.inst-cli');
    await fs.mkdir(dir, { recursive: true });

    // Write file
    await fs.writeFile(INST_CONFIG_PATH, content, 'utf-8');
    log.info('inst.yml saved successfully');

    return {
      success: true,
      message: 'Configuration saved successfully'
    };
  } catch (error: any) {
    log.error('Error saving inst.yml:', error);
    return {
      success: false,
      message: error.message || 'Failed to save configuration'
    };
  }
}

/**
 * Get inst_domain from inst.yml configuration file
 */
export async function getInstDomain(): Promise<string | null> {
  try {
    const instConfigContent = await fs.readFile(INST_CONFIG_PATH, 'utf-8');
    const instConfig: any = yaml.load(instConfigContent);
    return instConfig?.inst?.inst_domain || null;
  } catch (error: any) {
    if (error.code !== 'ENOENT') {
      log.error('Error reading inst_domain from inst.yml:', error);
    }
    return null;
  }
}
