const path = require('path');
const fs = require('fs');
const { DIRS, ensureDir } = require('./utils');

const AUTH_CONFIG_PATH = path.join(DIRS.qaContext, 'auth.json');
const CREDENTIALS_PATH = path.join(DIRS.auth, 'credentials.json');
const STORAGE_PATH = path.join(DIRS.auth, 'storage-state.json');

function readJSON(filePath) {
  if (!fs.existsSync(filePath)) return null;
  try { return JSON.parse(fs.readFileSync(filePath, 'utf-8')); } catch { return null; }
}

function writeJSON(filePath, data) {
  ensureDir(path.dirname(filePath));
  fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');
}

const auth = {

  // ── Auth Config (.qa-context/auth.json) ──

  getConfig() {
    return readJSON(AUTH_CONFIG_PATH) || {
      methods: [],
      session: { storage_path: STORAGE_PATH, last_refreshed: null },
    };
  },

  saveConfig(config) {
    writeJSON(AUTH_CONFIG_PATH, config);
  },

  updateMethod(method) {
    const config = this.getConfig();
    const idx = config.methods.findIndex(m => m.id === method.id);
    if (idx >= 0) config.methods[idx] = method;
    else config.methods.push(method);
    this.saveConfig(config);
    return config;
  },

  hasMethod() {
    const config = this.getConfig();
    return config.methods.length > 0;
  },

  // ── Credentials (.auth/credentials.json) ──

  saveCredentials(username, password, options = {}) {
    const creds = { username, password, url: options.url || '', updated_at: new Date().toISOString() };
    writeJSON(CREDENTIALS_PATH, creds);

    const config = this.getConfig();
    if (!config.methods.find(m => m.id === 'main-login')) {
      this.updateMethod({
        id: 'main-login',
        type: 'form',
        detected_at: new Date().toISOString(),
        login_url: options.url || '/login',
        fields: [
          { name: 'username', selector: '', type: 'text' },
          { name: 'password', selector: '', type: 'password' },
        ],
        submit: '',
        success_indicator: '',
        last_verified: new Date().toISOString(),
        status: 'configured',
      });
    }

    return creds;
  },

  getCredentials() {
    return readJSON(CREDENTIALS_PATH) || null;
  },

  hasCredentials() {
    return this.getCredentials() !== null;
  },

  clearCredentials() {
    if (fs.existsSync(CREDENTIALS_PATH)) fs.unlinkSync(CREDENTIALS_PATH);
    if (fs.existsSync(STORAGE_PATH)) fs.unlinkSync(STORAGE_PATH);
  },

  // ── Session (.auth/storage-state.json) ──

  saveSession(page) {
    throw new Error('saveSession requires Playwright page — use from AI agent or Playwright context');
  },

  getStorageStatePath() {
    return STORAGE_PATH;
  },

  hasSession() {
    return fs.existsSync(STORAGE_PATH);
  },

  clearSession() {
    if (fs.existsSync(STORAGE_PATH)) fs.unlinkSync(STORAGE_PATH);
  },

  // ── Login Steps Generator ──

  getLoginSteps(methodId) {
    const config = this.getConfig();
    const method = config.methods.find(m => m.id === (methodId || 'main-login'));
    if (!method) return null;

    const creds = this.getCredentials();
    if (!creds) return null;

    return {
      url: method.login_url || creds.url || '/login',
      fields: method.fields.map(f => ({
        selector: f.selector,
        value: f.name === 'username' || f.name === 'email' ? creds.username : creds.password,
      })),
      submit: method.submit,
      success: method.success_indicator,
    };
  },

  generateSetupCode() {
    const config = this.getConfig();
    const method = config.methods.find(m => m.id === 'main-login');
    const creds = this.getCredentials();
    if (!method || !creds) return null;

    const storagePath = STORAGE_PATH.replace(/\\/g, '/');
    const fields = method.fields.map(f => {
      const val = f.name === 'username' || f.name === 'email' ? 'credentials.username' : 'credentials.password';
      return `    await page.locator('${f.selector || ''}').fill(${val});`;
    }).join('\n');

    return `import { test as setup, expect } from '@playwright/test';
import path from 'path';

const AUTH_FILE = path.resolve(__dirname, '..', '${storagePath}');
const CREDENTIALS = require('${CREDENTIALS_PATH.replace(/\\/g, '/')}');

setup('authenticate', async ({ page }) => {
  await page.goto('${method.login_url || creds.url || '/'}');
${fields}
  await page.locator('${method.submit || ''}').click();
  await page.waitForURL('**${method.success_indicator || ''}**');
  await page.context().storageState({ path: AUTH_FILE });
});`;
  },

  // ── Auth Failure Detection ──

  isAuthFailure(error) {
    if (!error) return false;
    const msg = typeof error === 'string' ? error : (error.message || error.error || '');
    const patterns = [
      'login', 'unauthorized', 'unauthenticated', '401', '403',
      'session expired', 'invalid token', 'redirected to login',
      'sign in', 'authentication required', 'credentials',
    ];
    return patterns.some(p => msg.toLowerCase().includes(p));
  },

  // ── Init ──

  init() {
    ensureDir(DIRS.auth);

    if (!fs.existsSync(AUTH_CONFIG_PATH)) {
      this.saveConfig({
        methods: [],
        session: { storage_path: STORAGE_PATH, last_refreshed: null },
      });
    }

    const gitignorePath = path.join(DIRS.auth, '.gitignore');
    if (!fs.existsSync(gitignorePath)) {
      fs.writeFileSync(gitignorePath, '# Auth credentials and Playwright storage state\n*\n', 'utf-8');
    }
  },
};

module.exports = auth;
