import http from "node:http"
import fs from "node:fs"
import path from "node:path"
import { spawn } from "node:child_process"
import { fileURLToPath } from "node:url"

const __dirname = path.dirname(fileURLToPath(import.meta.url))
const ROOT = path.resolve(__dirname, "..")

// ── Load .env.local ──────────────────────────────────────────────
try {
  const envPath = path.join(ROOT, ".env.local")
  const envContent = fs.readFileSync(envPath, "utf-8")
  for (const line of envContent.split("\n")) {
    const trimmed = line.trim()
    if (!trimmed || trimmed.startsWith("#")) continue
    const eqIdx = trimmed.indexOf("=")
    if (eqIdx === -1) continue
    const k = trimmed.substring(0, eqIdx).trim()
    let v = trimmed.substring(eqIdx + 1).trim()
    if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) v = v.slice(1, -1)
    if (!process.env[k]) process.env[k] = v
  }
  console.log("Loaded .env.local")
} catch {
  // .env.local may not exist, ignore
}

// ── Config from env ─────────────────────────────────────────────
const PORT = parseInt(process.env.AI_PORT || "3001", 10)
const HOST = process.env.AI_HOST || "0.0.0.0"
const OLLAMA_URL = process.env.OLLAMA_BASE_URL || "http://localhost:11434"
const MODEL = process.env.AI_MODEL || "llama3.2:3b"
const DATABASE_URL = process.env.DATABASE_URL
const JOBS_PATH = process.env.JOBS_PATH || path.join(ROOT, "data", "ai", "jobs.jsonl")
const AI_MD_PATH = process.env.AI_MD_PATH || path.join(ROOT, "data", "ai", "ai.md")

// ── Setup state ──────────────────────────────────────────────────
let pullProcess = null
let pullProgress = { status: "idle", progress: 0, message: "" }

// ── Job loading ─────────────────────────────────────────────────
function loadJobs() {
  try {
    const content = fs.readFileSync(JOBS_PATH, "utf-8")
    const jobs = content
      .split("\n")
      .map((l) => l.trim())
      .filter(Boolean)
      .map((l) => {
        try {
          return JSON.parse(l)
        } catch {
          return null
        }
      })
      .filter(Boolean)
    console.log(`Loaded ${jobs.length} job categories`)
    return jobs
  } catch (e) {
    console.error(`Failed to load jobs from ${JOBS_PATH}:`, e.message)
    return []
  }
}

// ── ai.md management ────────────────────────────────────────────
function readInstructions() {
  try {
    return fs.readFileSync(AI_MD_PATH, "utf-8")
  } catch {
    return ""
  }
}

function writeInstructions(content) {
  fs.writeFileSync(AI_MD_PATH, content, "utf-8")
  return content
}

function appendToImprovementLog(entry) {
  const current = readInstructions()
  const timestamp = new Date().toISOString().replace("T", " ").substring(0, 16)
  const logEntry = `\n- ${timestamp} — ${entry}`
  const logSection = "\n## Improvement Log"
  const logIndex = current.indexOf(logSection)
  if (logIndex !== -1) {
    const afterLog = current.substring(logIndex + logSection.length)
    const nextSectionIndex = afterLog.search(/\n## /)
    if (nextSectionIndex !== -1) {
      const insertAt = logIndex + logSection.length + nextSectionIndex
      const updated = current.substring(0, insertAt) + logEntry + "\n" + current.substring(insertAt)
      writeInstructions(updated)
      return updated
    }
    writeInstructions(current + logEntry + "\n")
    return current + logEntry + "\n"
  }
  const updated = current + `\n${logSection}\n${logEntry}\n`
  writeInstructions(updated)
  return updated
}

// ── Chat handler ────────────────────────────────────────────────
async function scrapeFacebook() {
  const profilePath = process.env.FX_PROFILE || ""
  const urlPath = `/scrape/facebook?force=true${profilePath ? `&profile_path=${encodeURIComponent(profilePath)}` : ""}`
  const logPath = "C:\\Users\\USER-PC\\AppData\\Local\\Temp\\opencode\\ai-scrape-debug.log"
  try {
    const body = await new Promise((resolve, reject) => {
      const req = http.request({ hostname: "127.0.0.1", port: 3008, path: urlPath, method: "POST", timeout: 360000 }, (res) => {
        let data = ""
        res.on("data", (c) => data += c)
        res.on("end", () => resolve(data))
        res.on("error", reject)
      })
      req.on("timeout", () => { req.destroy(); reject(new Error("timeout")) })
      req.on("error", reject)
      req.end()
    })
    const data = JSON.parse(body)
    return data
  } catch (e) {
    return null
  }
}

function formatLeads(leads) {
  if (!leads || leads.length === 0) return "No leads found from the latest scrape."
  let output = `**${leads.length} leads found:**\n\n`
  for (let i = 0; i < leads.length; i++) {
    const l = leads[i]
    output += `${i + 1}. ${l.title || "No title"}\n`
    if (l.author) output += `   Author: ${l.author}\n`
    if (l.date) output += `   Date: ${l.date}\n`
    if (l.url) output += `   URL: ${l.url}\n`
    output += "\n"
  }
  return output.trim()
}

async function handleChat(userMessage, userId, userRole) {
  const lowerMsg = userMessage.toLowerCase()
  const triggerWords = ["lists", "listings", "leads", "recent leads", "pull leads", "show me leads", "show listings"]

  if (triggerWords.some(w => lowerMsg.includes(w))) {
    const result = await scrapeFacebook()
    if (result && result.success) {
      return formatLeads(result.leads)
    }
    return "Scraper returned no results or encountered an error. Try again later."
  }

  const jobs = loadedJobs
  const instructions = readInstructions()

  const jobList = jobs
    .map((j) => `- ${j.job_title} (${j.industry}): ${j.description}`)
    .join("\n")

  const systemPrompt = `You are a Sales AI Assistant for Coast IT CRM. Your role is to help salespeople with tips, strategies, and guidance.

Available job categories to target:
${jobList}

Current instructions:
${instructions}

Provide concise, actionable sales advice. When asked about a specific job category, give targeted tips on finding and engaging prospects in that field. Keep responses under 300 words unless asked for detail.`

  const ollamaRes = await fetch(`${OLLAMA_URL}/api/chat`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      model: MODEL,
      messages: [
        { role: "system", content: systemPrompt },
        { role: "user", content: userMessage },
      ],
      stream: false,
      options: { temperature: 0.7, num_predict: 1024 },
    }),
  })

  if (!ollamaRes.ok) {
    const text = await ollamaRes.text()
    throw new Error(`Ollama error (${ollamaRes.status}): ${text}`)
  }

  const data = await ollamaRes.json()
  const responseText = data.message?.content || ""

  // Try to persist to DB (best-effort)
  try {
    if (pgPool && userId) {
      await pgPool.query(
        "INSERT INTO ai_conversations (id, user_id, role, message, response) VALUES ($1, $2, $3, $4, $5)",
        [crypto.randomUUID(), userId, userRole || "sales", userMessage, responseText]
      )
    }
  } catch {
    // table might not exist, ignore
  }

  return responseText
}

// ── PG pool (lazy init) ────────────────────────────────────────
let pgPool = null
async function initPg() {
  if (!DATABASE_URL) return
  try {
    const { default: pg } = await import("pg")
    pgPool = new pg.Pool({ connectionString: DATABASE_URL, max: 5 })
    await pgPool.query("SELECT 1")
    console.log("Connected to PostgreSQL")
  } catch (e) {
    console.warn("PostgreSQL unavailable (AI convos won't be saved):", e.message)
  }
}

// ── Request router ─────────────────────────────────────────────
const loadedJobs = loadJobs()

function sendJSON(res, status, data) {
  res.writeHead(status, { "Content-Type": "application/json" })
  res.end(JSON.stringify(data))
}

function parseBody(req) {
  return new Promise((resolve, reject) => {
    let body = ""
    req.on("data", (chunk) => (body += chunk))
    req.on("end", () => {
      try {
        resolve(JSON.parse(body))
      } catch {
        reject(new Error("Invalid JSON"))
      }
    })
    req.on("error", reject)
  })
}

function parseURL(req) {
  const url = new URL(req.url, `http://${req.headers.host || "localhost"}`)
  return { pathname: url.pathname, searchParams: url.searchParams }
}

const server = http.createServer(async (req, res) => {
  // CORS
  res.setHeader("Access-Control-Allow-Origin", "*")
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
  res.setHeader("Access-Control-Allow-Headers", "Content-Type")

  if (req.method === "OPTIONS") {
    res.writeHead(204)
    res.end()
    return
  }

  const { pathname } = parseURL(req)

  try {
    // GET /splash — loading screen
    if (req.method === "GET" && pathname === "/splash") {
      const splashPath = path.join(ROOT, "splash.html")
      if (fs.existsSync(splashPath)) {
        const html = fs.readFileSync(splashPath, "utf-8")
        res.writeHead(200, { "Content-Type": "text/html" })
        res.end(html)
        return
      }
      sendJSON(res, 200, { status: "ok" })
      return
    }

    // GET /health
    if (req.method === "GET" && pathname === "/health") {
      return sendJSON(res, 200, { status: "ok", model: MODEL })
    }

    // GET /status — combined health of all services
    if (req.method === "GET" && pathname === "/status") {
      const { default: http } = await import("http")
      const results = { ai: true }
      // Check scraper
      try {
        await new Promise((resolve, reject) => {
          const r = http.get("http://127.0.0.1:3008/health", { timeout: 3000 }, (res) => { res.resume(); resolve() })
          r.on("error", reject)
        })
        results.scraper = true
      } catch { results.scraper = false }
      // Check frontend
      try {
        await new Promise((resolve, reject) => {
          const r = http.get("http://127.0.0.1:3006", { timeout: 3000 }, (res) => { res.resume(); resolve() })
          r.on("error", reject)
        })
        results.frontend = true
      } catch { results.frontend = false }
      return sendJSON(res, 200, results)
    }

    // ── Setup endpoints ─────────────────────────────────────────

    // GET /setup/status — check environment
    if (req.method === "GET" && pathname === "/setup/status") {
      const envExists = fs.existsSync(path.join(ROOT, ".env.local"))

      // Ollama check
      let ollamaRunning = false
      try {
        await fetch(`${OLLAMA_URL}/api/tags`, { signal: AbortSignal.timeout(3000) })
        ollamaRunning = true
      } catch {}

      // Model check
      let modelAvailable = false
      if (ollamaRunning) {
        try {
          const r = await fetch(`${OLLAMA_URL}/api/show`, {
            method: "POST", body: JSON.stringify({ name: MODEL }),
            signal: AbortSignal.timeout(5000),
          })
          modelAvailable = r.ok
        } catch {}
      }

      // Profile auto-detect
      let profilePath = process.env.FX_PROFILE || ""
      let profileDetected = !!profilePath
      if (!profileDetected) {
        try {
          const r = await fetch("http://127.0.0.1:3008/health", { signal: AbortSignal.timeout(2000) })
          if (r.ok) {
            const diag = await (await fetch("http://127.0.0.1:3008/setup/profile", { signal: AbortSignal.timeout(5000) })).json()
            if (diag.path) { profilePath = diag.path; profileDetected = true }
          }
        } catch {}
      }

      // Login check
      let facebookLoggedIn = false
      if (profileDetected) {
        try {
          const r = await fetch("http://127.0.0.1:3008/setup/check-login", {
            method: "POST", headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ profile_path: profilePath }),
            signal: AbortSignal.timeout(15000),
          })
          if (r.ok) { const d = await r.json(); facebookLoggedIn = d.logged_in === true }
        } catch {}
      }

      const firstRun = !envExists || !ollamaRunning || !profileDetected || !modelAvailable

      return sendJSON(res, 200, {
        first_run: firstRun,
        env_exists: envExists,
        ollama_running: ollamaRunning,
        model_available: modelAvailable,
        model_name: MODEL,
        profile_detected: profileDetected,
        profile_path: profilePath || null,
        facebook_logged_in: facebookLoggedIn,
      })
    }

    // POST /setup/profile — save profile path to .env.local
    if (req.method === "POST" && pathname === "/setup/profile") {
      const body = await parseBody(req)
      const profilePath = (body.path || "").trim()
      if (!profilePath) return sendJSON(res, 400, { error: "Path required" })
      if (!fs.existsSync(profilePath)) return sendJSON(res, 400, { error: "Path does not exist" })

      const envPath = path.join(ROOT, ".env.local")
      let content = ""
      try { content = fs.readFileSync(envPath, "utf-8") } catch {}
      const lines = content.split("\n")
      let found = false
      for (let i = 0; i < lines.length; i++) {
        if (lines[i].trim().startsWith("FX_PROFILE=")) {
          lines[i] = `FX_PROFILE=${profilePath}`
          found = true
          break
        }
      }
      if (!found) lines.push(`FX_PROFILE=${profilePath}`)
      fs.writeFileSync(envPath, lines.join("\n"), "utf-8")
      process.env.FX_PROFILE = profilePath
      return sendJSON(res, 200, { success: true, path: profilePath })
    }

    // POST /setup/check-login — verify Facebook login in the given profile
    if (req.method === "POST" && pathname === "/setup/check-login") {
      const body = await parseBody(req)
      const profilePath = body.profile_path || process.env.FX_PROFILE || ""
      if (!profilePath) return sendJSON(res, 200, { logged_in: false, reason: "no_profile" })
      try {
        const r = await fetch("http://127.0.0.1:3008/setup/check-login", {
          method: "POST", headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ profile_path: profilePath }),
          signal: AbortSignal.timeout(20000),
        })
        if (r.ok) { const d = await r.json(); return sendJSON(res, 200, d) }
      } catch {}
      return sendJSON(res, 200, { logged_in: false, reason: "scraper_unavailable" })
    }

    // POST /setup/ollama/pull — start pulling the model
    if (req.method === "POST" && pathname === "/setup/ollama/pull") {
      if (pullProcess) return sendJSON(res, 200, { status: "already_running" })
      pullProgress = { status: "downloading", progress: 0, message: "Starting..." }
      const isWin = process.platform === "win32"
      const cmd = isWin ? "ollama.exe" : "ollama"
      pullProcess = spawn(cmd, ["pull", MODEL], { stdio: ["ignore", "pipe", "pipe"] })

      pullProcess.stdout.on("data", (data) => {
        const text = data.toString()
        pullProgress.message = text.trim()
        // Extract percentage from patterns like "pulling xxxx... 45%"
        const m = text.match(/(\d+)%/)
        if (m) pullProgress.progress = parseInt(m[1], 10)
      })
      pullProcess.on("close", (code) => {
        pullProcess = null
        pullProgress.status = code === 0 ? "done" : "failed"
        if (code === 0) pullProgress.progress = 100
      })
      return sendJSON(res, 200, { status: "started" })
    }

    // GET /setup/ollama/pull/progress
    if (req.method === "GET" && pathname === "/setup/ollama/pull/progress") {
      return sendJSON(res, 200, pullProgress)
    }

    // GET /ai/jobs
    if (req.method === "GET" && pathname === "/ai/jobs") {
      return sendJSON(res, 200, { jobs: loadedJobs })
    }

    // GET /ai/instructions
    if (req.method === "GET" && pathname === "/ai/instructions") {
      const instructions = readInstructions()
      return sendJSON(res, 200, { success: true, instructions })
    }

    // POST /ai/instructions
    if (req.method === "POST" && pathname === "/ai/instructions") {
      const body = await parseBody(req)
      if (body.content) {
        writeInstructions(body.content)
      } else if (body.entry) {
        appendToImprovementLog(body.entry)
      }
      return sendJSON(res, 200, {
        success: true,
        instructions: readInstructions(),
      })
    }

    // POST /ai/chat
    if (req.method === "POST" && pathname === "/ai/chat") {
      const startTime = Date.now()
      const chunks = []
      req.on("data", c => chunks.push(c))
      req.on("end", () => {
        const rawBody = Buffer.concat(chunks).toString()
        try { fs.appendFileSync("C:\\Users\\USER-PC\\AppData\\Local\\Temp\\opencode\\ai-req-log.txt",
          `${new Date().toISOString()} headers=${JSON.stringify(req.headers)} body=${rawBody}\n`) } catch {}
        try {
          const body = JSON.parse(rawBody)
          // Continue processing
          processRequest(req, res, body, startTime)
        } catch {
          sendJSON(res, 400, { error: "Invalid JSON" })
        }
      })
      return
    }

// Separate handler
async function processRequest(req, res, body, startTime) {
      const { message, user_id, user_role } = body

      if (!message) {
        return sendJSON(res, 400, { error: "message is required" })
      }

      const validRoles = ["sales", "admin", "super_admin"]
      if (user_role && !validRoles.includes(user_role)) {
        return sendJSON(res, 403, { error: "Forbidden" })
      }

      const response = await handleChat(message, user_id || "", user_role || "sales")
      return sendJSON(res, 200, { response })
    }

    // 404
    sendJSON(res, 404, { error: "Not found" })
  } catch (err) {
    console.error("Request error:", err)
    sendJSON(res, 500, { error: err.message })
  }
})

// ── Start ───────────────────────────────────────────────────────
server.listen(PORT, HOST, () => {
  console.log(`CRM AI server listening on http://${HOST}:${PORT}`)
  console.log(`  Model: ${MODEL}`)
  console.log(`  Ollama: ${OLLAMA_URL}`)
})

initPg()
