import { Injectable, Logger } from '@nestjs/common';
import fs from 'node:fs/promises';
import path from 'node:path';
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';

const execFileAsync = promisify(execFile);

export interface WorkspaceProject {
  id: string;
  ownerType: 'user' | 'team';
  userId: string;
  teamId: string | null;
}

@Injectable()
export class WorkspaceService {
  private readonly logger = new Logger(WorkspaceService.name);
  private readonly mosaicRoot: string;

  constructor() {
    this.mosaicRoot = process.env['MOSAIC_ROOT'] ?? '/opt/mosaic';
  }

  /**
   * Resolve the workspace path for a project.
   * Solo: $MOSAIC_ROOT/.workspaces/users/<userId>/<projectId>/
   * Team: $MOSAIC_ROOT/.workspaces/teams/<teamId>/<projectId>/
   */
  resolvePath(project: WorkspaceProject): string {
    if (project.ownerType === 'team' && project.teamId) {
      return path.join(this.mosaicRoot, '.workspaces', 'teams', project.teamId, project.id);
    }
    return path.join(this.mosaicRoot, '.workspaces', 'users', project.userId, project.id);
  }

  /**
   * Create a workspace directory and initialize it as a git repo.
   * If repoUrl is provided, clone instead of init.
   */
  async create(project: WorkspaceProject, repoUrl?: string): Promise<string> {
    const workspacePath = this.resolvePath(project);

    // Create directory
    await fs.mkdir(workspacePath, { recursive: true });

    if (repoUrl) {
      // Clone existing repo
      await execFileAsync('git', ['clone', repoUrl, '.'], { cwd: workspacePath });
      this.logger.log(`Cloned ${repoUrl} into workspace ${workspacePath}`);
    } else {
      // Init new git repo
      await execFileAsync('git', ['init'], { cwd: workspacePath });
      await execFileAsync('git', ['commit', '--allow-empty', '-m', 'Initial workspace commit'], {
        cwd: workspacePath,
        env: {
          ...process.env,
          GIT_AUTHOR_NAME: 'Mosaic',
          GIT_AUTHOR_EMAIL: 'mosaic@localhost',
          GIT_COMMITTER_NAME: 'Mosaic',
          GIT_COMMITTER_EMAIL: 'mosaic@localhost',
        },
      });
      this.logger.log(`Initialized git workspace at ${workspacePath}`);
    }

    // Create standard docs structure
    await fs.mkdir(path.join(workspacePath, 'docs', 'plans'), { recursive: true });
    await fs.mkdir(path.join(workspacePath, 'docs', 'reports'), { recursive: true });
    this.logger.log(`Created docs structure at ${workspacePath}`);

    return workspacePath;
  }

  /**
   * Delete a workspace directory recursively.
   */
  async delete(project: WorkspaceProject): Promise<void> {
    const workspacePath = this.resolvePath(project);
    try {
      await fs.rm(workspacePath, { recursive: true, force: true });
      this.logger.log(`Deleted workspace at ${workspacePath}`);
    } catch (err) {
      this.logger.warn(`Failed to delete workspace at ${workspacePath}: ${err}`);
    }
  }

  /**
   * Check whether the workspace directory exists.
   */
  async exists(project: WorkspaceProject): Promise<boolean> {
    const workspacePath = this.resolvePath(project);
    try {
      await fs.access(workspacePath);
      return true;
    } catch {
      return false;
    }
  }

  /**
   * Create the base user workspace directory (call on user registration).
   */
  async createUserRoot(userId: string): Promise<void> {
    const userRoot = path.join(this.mosaicRoot, '.workspaces', 'users', userId);
    await fs.mkdir(userRoot, { recursive: true });
  }

  /**
   * Create the base team workspace directory (call on team creation).
   */
  async createTeamRoot(teamId: string): Promise<void> {
    const teamRoot = path.join(this.mosaicRoot, '.workspaces', 'teams', teamId);
    await fs.mkdir(teamRoot, { recursive: true });
  }
}
