import { promises as fs } from 'fs';
import path from 'path';
import os from 'os';
import { AtlasConfig, ProjectMode, StorageMode, ProjectDetectionResult, DashboardConfig } from './types.js';
import { StorageManager } from '../storage/storage-manager.js';

export class ConfigManager {
  private config: AtlasConfig;
  private configPath: string | null = null;
  private storageManager: StorageManager;
  
  constructor() {
    this.storageManager = new StorageManager();
    this.config = this.getDefaultConfig();
  }

  private getDefaultConfig(): AtlasConfig {
    return {
      projectMode: 'new',
      workspaceRoot: process.cwd(),
      dataLocation: '.atlas/',
      integration: {
        respectGitignore: true,
        preserveExisting: true,
        modules: {
          kanban: true,
          development: true,
          documentation: true,
          'product-requirements': true,
          agile: true,
        },
      },
      features: {
        tddEnforcement: 'strict',
        autoInit: false,
        autoBackup: true,
      },
      storage: {
        mode: 'local',
        isolation: 'project',
      },
      webDashboard: {
        enabled: true,
        port: 3001,
        host: 'localhost',
        autoOpen: false,
        features: {
          performance: true,
          security: true,
          agile: true,
          errors: true
        },
        realTimeUpdates: true,
        exportEnabled: true
      },
      version: '1.0.0',
    };
  }

  private async getConfigPath(): Promise<string> {
    // Store config in the storage location, not in project root by default
    const location = await this.storageManager.getStorageLocation();
    return path.join(location.config, 'atlas.config.json');
  }

  async load(): Promise<void> {
    // First try to load from project root
    try {
      const localConfigPath = path.join(process.cwd(), 'atlas.config.json');
      const data = await fs.readFile(localConfigPath, 'utf-8');
      this.config = { ...this.getDefaultConfig(), ...JSON.parse(data) };
      return;
    } catch {
      // Not in project root, continue
    }
    
    // Then try from storage location
    try {
      if (!this.configPath) {
        this.configPath = await this.getConfigPath();
      }
      const data = await fs.readFile(this.configPath, 'utf-8');
      this.config = { ...this.getDefaultConfig(), ...JSON.parse(data) };
    } catch (error) {
      // Use default config if file doesn't exist
      this.config = this.getDefaultConfig();
    }
  }

  async save(): Promise<void> {
    // Save to current directory for tests/local use
    const localConfigPath = path.join(process.cwd(), 'atlas.config.json');
    await fs.writeFile(localConfigPath, JSON.stringify(this.config, null, 2));
  }

  async detectProject(): Promise<ProjectDetectionResult> {
    const result: ProjectDetectionResult = {
      hasGit: false,
      hasPackageJson: false,
      hasTsConfig: false,
      hasTests: false,
      suggestedMode: 'new',
      existingTools: [],
    };

    // Check for Git
    try {
      await fs.access(path.join(process.cwd(), '.git'));
      result.hasGit = true;
      result.existingTools.push('git');
    } catch {}

    // Check for Node.js project
    try {
      await fs.access(path.join(process.cwd(), 'package.json'));
      result.hasPackageJson = true;
      result.projectType = 'node';
      
      const packageJson = JSON.parse(
        await fs.readFile(path.join(process.cwd(), 'package.json'), 'utf-8')
      );
      
      // Detect test framework
      const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
      if (deps.jest || deps['@jest/core']) {
        result.testFramework = 'jest';
        result.hasTests = true;
      } else if (deps.mocha) {
        result.testFramework = 'mocha';
        result.hasTests = true;
      } else if (deps.vitest) {
        result.testFramework = 'vitest';
        result.hasTests = true;
      }

      // Check for existing PM tools
      if (deps['@atlassian/jira']) result.existingTools.push('jira');
      if (deps.trello) result.existingTools.push('trello');
    } catch {}

    // Check for TypeScript
    try {
      await fs.access(path.join(process.cwd(), 'tsconfig.json'));
      result.hasTsConfig = true;
      result.existingTools.push('typescript');
    } catch {}

    // Determine suggested mode
    if (result.hasGit && result.hasPackageJson) {
      result.suggestedMode = 'existing';
    }

    // Check for monorepo indicators
    try {
      const files = await fs.readdir(process.cwd());
      const hasMultiplePackageJsons = 0;
      
      for (const file of files) {
        const filePath = path.join(process.cwd(), file);
        const stat = await fs.stat(filePath);
        
        if (stat.isDirectory() && !file.startsWith('.')) {
          try {
            await fs.access(path.join(filePath, 'package.json'));
            result.suggestedMode = 'multi-repo';
            break;
          } catch {}
        }
      }
      
      // Check for lerna, yarn workspaces, etc.
      if (files.includes('lerna.json') || files.includes('pnpm-workspace.yaml')) {
        result.suggestedMode = 'multi-repo';
      }
    } catch {}

    return result;
  }

  async getStoragePath(): Promise<string> {
    const location = await this.storageManager.getStorageLocation();
    return location.data;
  }
  
  // Backwards compatibility - sync version
  getDataPath(): string {
    // Return based on current config
    if (this.config.storage?.mode === 'home' && this.config.projectName) {
      return path.join(os.homedir(), '.atlas', 'projects', this.config.projectName);
    }
    if (this.config.storage?.mode === 'custom' && this.config.storage?.path) {
      return this.config.storage.path;
    }
    return path.join(this.config.workspaceRoot || process.cwd(), '.atlas');
  }
  
  getStorageManager(): StorageManager {
    return this.storageManager;
  }

  get(): AtlasConfig {
    return { ...this.config };
  }

  set(config: Partial<AtlasConfig>): void {
    this.config = { ...this.config, ...config };
  }

  isModuleEnabled(module: string): boolean {
    const modules = this.config.integration?.modules as any;
    return modules?.[module] ?? true;
  }

  getProjectMode(): ProjectMode {
    return this.config.projectMode;
  }

  isMultiRepo(): boolean {
    return this.config.projectMode === 'multi-repo';
  }

  getRepositories(): NonNullable<AtlasConfig['repositories']> {
    return this.config.repositories || [];
  }

  isDashboardEnabled(): boolean {
    return this.config.webDashboard?.enabled ?? true;
  }

  getDashboardConfig(): DashboardConfig {
    const defaults = this.getDefaultConfig().webDashboard!;
    return {
      ...defaults,
      ...this.config.webDashboard
    } as Required<DashboardConfig>;
  }

  updateDashboardConfig(dashboardConfig: Partial<DashboardConfig>): void {
    this.config.webDashboard = {
      ...this.config.webDashboard,
      ...dashboardConfig
    };
  }
}