const fs = require('fs');
const path = require('path');

const ROOT = path.resolve(__dirname, '..');

const CONFIG_PATH = path.join(ROOT, '.qa-workflow.json');

function extractUrl(script) {
  if (!script) return null;
  const portMatch = script.match(/--port\s+(\d+)/) || script.match(/-p\s+(\d+)/) || script.match(/PORT=(\d+)/);
  if (portMatch) return `http://localhost:${portMatch[1]}`;
  const urlMatch = script.match(/https?:\/\/[^\s"'`]+/);
  return urlMatch ? urlMatch[0] : null;
}

function autoDetectConfig() {
  const detected = {
    project: { name: '', description: '', url: '', environment: '' },
    browser: { type: 'chromium', cdpPort: 9222, headed: false },
    test: { timeout: 120000, retries: 0, workers: 1 },
    auth: { user: '', credentials: {} },
  };

  // Detect from package.json
  const pkgPath = path.join(ROOT, 'package.json');
  if (fs.existsSync(pkgPath)) {
    try {
      const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
      detected.project.name = pkg.name || path.basename(ROOT);
      detected.project.description = pkg.description || '';
      if (pkg.scripts) {
        const devScript = pkg.scripts.dev || pkg.scripts.start || pkg.scripts.serve || '';
        detected.project.url = extractUrl(devScript) || 'http://localhost:3000';
      }
    } catch {}
  } else {
    detected.project.name = path.basename(ROOT);
  }

  // Detect from docker-compose (first exposed port)
  const composePaths = ['docker-compose.yml', 'docker-compose.yaml', 'compose.yml', 'compose.yaml'];
  for (const cp of composePaths) {
    const cpPath = path.join(ROOT, cp);
    if (fs.existsSync(cpPath)) {
      try {
        const content = fs.readFileSync(cpPath, 'utf-8');
        const portMatch = content.match(/"(\d+):\d+"/) || content.match(/'(\d+):\d+'/);
        if (portMatch) detected.project.url = `http://localhost:${portMatch[1]}`;
        const envMatch = content.match(/COMPOSE_PROJECT_NAME[=:]\s*["']?([^"'\s]+)/);
        if (envMatch && !detected.project.name) detected.project.name = envMatch[1];
      } catch {}
    }
  }

  // Detect environment from .env
  const envPath = path.join(ROOT, '.env');
  if (fs.existsSync(envPath)) {
    try {
      const envContent = fs.readFileSync(envPath, 'utf-8');
      const appUrl = envContent.match(/APP_URL\s*=\s*(.+)/);
      if (appUrl) detected.project.url = appUrl[1].trim();
      const appEnv = envContent.match(/APP_ENV\s*=\s*(.+)/) || envContent.match(/NODE_ENV\s*=\s*(.+)/);
      if (appEnv) detected.project.environment = appEnv[1].trim();
    } catch {}
  }

  // Detect from README
  for (const readme of ['README.md', 'README.rst', 'README.txt']) {
    const rp = path.join(ROOT, readme);
    if (fs.existsSync(rp)) {
      try {
        const content = fs.readFileSync(rp, 'utf-8');
        const titleMatch = content.match(/^#\s+(.+)/m);
        if (titleMatch && !detected.project.name) detected.project.name = titleMatch[1].trim();
        const urlMatch = content.match(/https?:\/\/[^\s"')\]>]+/);
        if (urlMatch) detected.project.url = urlMatch[0].replace(/[.)]>]$/g, '');
        const descLine = content.split('\n').slice(1, 3).join(' ').replace(/^>?\s*/, '').substring(0, 300);
        if (descLine && !detected.project.description) detected.project.description = descLine;
      } catch {}
    }
  }

  // Detect browser type from playwright config
  const pwPaths = ['playwright.config.ts', 'playwright.config.js'];
  for (const pw of pwPaths) {
    const pwPath = path.join(ROOT, pw);
    if (fs.existsSync(pwPath)) {
      try {
        const content = fs.readFileSync(pwPath, 'utf-8');
        if (/\bedge\b/i.test(content) || /\bmsedge\b/i.test(content)) detected.browser.type = 'edge';
        if (/webkit/i.test(content)) detected.browser.type = 'webkit';
      } catch {}
    }
  }

  // Detect project type from directory patterns
  if (fs.existsSync(path.join(ROOT, 'src', 'app')) || fs.existsSync(path.join(ROOT, 'angular.json'))) {
    detected.project.environment = detected.project.environment || 'Angular App';
  } else if (fs.existsSync(path.join(ROOT, 'src', 'pages')) && fs.existsSync(path.join(ROOT, 'next.config.js'))) {
    detected.project.environment = detected.project.environment || 'Next.js App';
  } else if (fs.existsSync(path.join(ROOT, 'src')) && !detected.project.environment) {
    detected.project.environment = 'Web Application';
  } else if (fs.existsSync(path.join(ROOT, 'app.py')) || fs.existsSync(path.join(ROOT, 'manage.py'))) {
    detected.project.environment = 'Python Web App';
  }

  return detected;
}

function loadConfig() {
  const defaults = {
    project: { name: 'my-project', description: '', url: 'http://localhost:3000', environment: 'Development' },
    browser: { type: 'chromium', cdpPort: 9222, headed: false },
    test: { timeout: 120000, retries: 0, workers: 1, stableSelectors: true },
    auth: { user: '', credentials: {} },
  };

  let base = { ...defaults };
  if (fs.existsSync(CONFIG_PATH)) {
    try {
      const userConfig = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
      deepMerge(base, userConfig);
      return base;
    } catch (e) {
      console.warn(`  ⚠  Failed to parse .qa-workflow.json: ${e.message}`);
    }
  }

  // No config file — auto-detect from project, then fill gaps with defaults
  const detected = autoDetectConfig();
  deepMerge(base, detected);
  return base;
}

function deepMerge(target, source) {
  for (const key of Object.keys(source)) {
    if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
      if (!target[key]) target[key] = {};
      deepMerge(target[key], source[key]);
    } else {
      target[key] = source[key];
    }
  }
}

let CONFIG = loadConfig();

function reloadConfig() {
  CONFIG = loadConfig();
  return CONFIG;
}

const DIRS = {
  userStory: path.join(ROOT, 'user-story'),
  specs: path.join(ROOT, 'specs'),
  tests: path.join(ROOT, 'tests'),
  testResults: path.join(ROOT, 'test-results'),
  allureResults: path.join(ROOT, 'allure-results'),
  scratch: path.join(ROOT, 'scratch'),
  docs: path.join(ROOT, 'docs'),
  scripts: path.join(ROOT, 'scripts'),
  qaContext: path.join(ROOT, '.qa-context'),
  auth: path.join(ROOT, '.auth'),
};

function ensureDir(dir) {
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
}

function listFiles(dir, ext) {
  if (!fs.existsSync(dir)) return [];
  return fs.readdirSync(dir)
    .filter(f => f.endsWith(ext))
    .sort();
}

function listUserStories() {
  return listFiles(DIRS.userStory, '.md');
}

function listTestPlans() {
  return listFiles(DIRS.specs, '.md');
}

function listTestSpecs() {
  return listFiles(DIRS.tests, '.spec.ts');
}

function readMarkdown(filePath) {
  return fs.readFileSync(filePath, 'utf-8');
}

function writeMarkdown(filePath, content) {
  ensureDir(path.dirname(filePath));
  fs.writeFileSync(filePath, content, 'utf-8');
}

function parseUserStory(filePath) {
  const content = readMarkdown(filePath);
  const story = { content, metadata: {} };

  const idMatch = content.match(/\*\*Story ID\*\*:\s*(\S+)/);
  if (idMatch) story.id = idMatch[1];

  const titleMatch = content.match(/^#\s+(.+)$/m);
  if (titleMatch) story.title = titleMatch[1].trim();

  const titleMetaMatch = content.match(/\*\*Title\*\*:\s*(.+)/);
  if (titleMetaMatch) story.metaTitle = titleMetaMatch[1].trim();

  const descMatch = content.match(/## Description\s*\n(.+?)(?=\n## |\n---|$)/s);
  if (descMatch) story.description = descMatch[1].trim();

  const precondMatch = content.match(/## Preconditions\s*\n(.+?)(?=\n## |\n---|$)/s);
  if (precondMatch) {
    story.preconditions = precondMatch[1]
      .split('\n')
      .filter(l => l.trim().startsWith('-'))
      .map(l => l.replace(/^- /, '').trim());
  }

  const acMatch = content.match(/## Acceptance Criteria\s*\n(.+?)(?=\n## |\n---|$)/s);
  if (acMatch) {
    story.acceptanceCriteria = acMatch[1].trim();
  }

  return story;
}

function slugify(text) {
  return text
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-|-$/g, '');
}

function timestamp() {
  return new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
}

function log(step, msg) {
  const ts = new Date().toLocaleTimeString();
  console.log(`  [${ts}] [${step}] ${msg}`);
}

module.exports = { ROOT, DIRS, CONFIG, CONFIG_PATH, loadConfig, reloadConfig, autoDetectConfig, ensureDir, listFiles, listUserStories, listTestPlans, listTestSpecs, readMarkdown, writeMarkdown, parseUserStory, slugify, timestamp, log, extractUrl };
