import fs from 'node:fs';
import path from 'node:path';
import type { AdapterCommand } from './types.js';
import { hasComposerDependency, readComposerJson } from './composer.js';
import { PhpFrameworkAdapter } from './phpBase.js';

const DEV_HOST = '127.0.0.1';
const DEV_PORT = '8000';

function composeFileExists(root: string): boolean {
  return ['docker-compose.yml', 'docker-compose.yaml', 'compose.yml', 'compose.yaml'].some((name) =>
    fs.existsSync(path.join(root, name)),
  );
}

function sailScriptPath(root: string): string | null {
  const candidates = [
    path.join(root, 'vendor', 'bin', 'sail'),
    path.join(root, 'vendor', 'bin', 'sail.bat'),
  ];
  return candidates.find((file) => fs.existsSync(file)) ?? null;
}

/** True when laravel/sail is required and a compose file is present. */
export function laravelUsesSail(root: string): boolean {
  return Boolean(hasComposerDependency(readComposerJson(root), 'laravel/sail') && composeFileExists(root));
}

export class LaravelAdapter extends PhpFrameworkAdapter {
  readonly kind = 'laravel' as const;
  readonly label = 'Laravel';

  private get usesSail(): boolean {
    return hasComposerDependency(this.composerJson, 'laravel/sail') && composeFileExists(this.root);
  }

  devCommand(): AdapterCommand {
    if (this.usesSail) {
      const sail = sailScriptPath(this.root);
      if (sail) {
        // Sail is a bash script; invoke via bash so Windows+Git Bash/WSL and Unix share one path.
        return {
          command: 'bash',
          args: [sail.replace(/\\/g, '/'), 'up'],
          cwd: this.root,
        };
      }
      return {
        command: 'docker',
        args: ['compose', 'up'],
        cwd: this.root,
      };
    }

    return {
      command: 'php',
      args: ['artisan', 'serve', `--host=${DEV_HOST}`, `--port=${DEV_PORT}`],
      cwd: this.root,
    };
  }

  readyPattern(): RegExp {
    if (this.usesSail) {
      return /(?:Container|Service).+(?:Started|Healthy|Running)|Listening on (https?:\/\/\S+)|APP_URL[=:].*(https?:\/\/\S+)|Local:\s+(https?:\/\/\S+)|Server running on \[?(https?:\/\/[^\s\]]+)/i;
    }
    // `php artisan serve` prints: "INFO  Server running on [http://127.0.0.1:8000]."
    return /Server running on \[?(https?:\/\/[^\s\]]+)/i;
  }

  describe(): Record<string, unknown> {
    const sail = this.usesSail;
    return {
      kind: this.kind,
      label: this.label,
      root: this.root,
      packageManager: this.packageManager,
      laravelVersion: this.composerJson?.require?.['laravel/framework'] ?? null,
      usesPest: Boolean(this.composerJson?.['require-dev']?.['pestphp/pest']),
      usesSail: sail,
      sailScript: sail ? sailScriptPath(this.root) : null,
      devUrl: sail ? 'http://localhost' : `http://${DEV_HOST}:${DEV_PORT}`,
      notes: sail
        ? 'Sail detected: start_dev_server uses `vendor/bin/sail up` (or docker compose up).'
        : undefined,
    };
  }
}
