/**
 * Knowledge tools: search_knowledge_base, search_manuals, get_hype_cycle
 */
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { pool } from "../db.js";

// Norton-Bass diffusion model (inline, since MCP server has separate build)
interface TechGen { name: string; speedGbps: number; formFactor: string; introYear: number; peakYear: number; p: number; q: number; m: number; k: number; t0: number; }

const TECH_GENS: TechGen[] = [
  { name: "1G SFP", speedGbps: 1, formFactor: "SFP", introYear: 2001, peakYear: 2012, p: 0.03, q: 0.38, m: 500, k: 0.45, t0: 2008 },
  { name: "10G SFP+", speedGbps: 10, formFactor: "SFP+", introYear: 2006, peakYear: 2018, p: 0.03, q: 0.42, m: 600, k: 0.50, t0: 2014 },
  { name: "25G SFP28", speedGbps: 25, formFactor: "SFP28", introYear: 2015, peakYear: 2022, p: 0.04, q: 0.45, m: 200, k: 0.55, t0: 2019 },
  { name: "40G QSFP+", speedGbps: 40, formFactor: "QSFP+", introYear: 2010, peakYear: 2019, p: 0.025, q: 0.35, m: 150, k: 0.40, t0: 2016 },
  { name: "100G QSFP28", speedGbps: 100, formFactor: "QSFP28", introYear: 2014, peakYear: 2024, p: 0.03, q: 0.40, m: 400, k: 0.48, t0: 2020 },
  { name: "400G QSFP-DD", speedGbps: 400, formFactor: "QSFP-DD", introYear: 2020, peakYear: 2027, p: 0.035, q: 0.50, m: 300, k: 0.52, t0: 2025 },
  { name: "800G OSFP", speedGbps: 800, formFactor: "OSFP", introYear: 2023, peakYear: 2029, p: 0.04, q: 0.55, m: 250, k: 0.55, t0: 2027 },
  { name: "1.6T OSFP-XD", speedGbps: 1600, formFactor: "OSFP-XD", introYear: 2025, peakYear: 2032, p: 0.03, q: 0.45, m: 180, k: 0.48, t0: 2030 },
  { name: "CPO", speedGbps: 1600, formFactor: "CPO", introYear: 2024, peakYear: 2033, p: 0.02, q: 0.30, m: 50, k: 0.35, t0: 2031 },
  { name: "400ZR Coherent", speedGbps: 400, formFactor: "QSFP-DD", introYear: 2021, peakYear: 2026, p: 0.04, q: 0.50, m: 80, k: 0.55, t0: 2024 },
  { name: "LPO", speedGbps: 800, formFactor: "LPO", introYear: 2024, peakYear: 2029, p: 0.035, q: 0.48, m: 100, k: 0.50, t0: 2027 },
];

function bassCumulative(t: number, p: number, q: number): number {
  const pq = p + q;
  const exp = Math.exp(-pq * t);
  return (1 - exp) / (1 + (q / p) * exp);
}

function bassRate(t: number, p: number, q: number): number {
  const pq = p + q;
  const exp = Math.exp(-pq * t);
  const d = 1 + (q / p) * exp;
  return (pq * pq / q) * (exp / (d * d));
}

function classifyHypePhase(progressRatio: number): string {
  if (progressRatio < 0.15) return "Innovation Trigger";
  if (progressRatio < 0.35) return "Peak of Inflated Expectations";
  if (progressRatio < 0.55) return "Trough of Disillusionment";
  if (progressRatio < 0.85) return "Slope of Enlightenment";
  if (progressRatio < 1.3) return "Plateau of Productivity";
  return "Legacy / Decline";
}

function findTech(query: string): TechGen | undefined {
  const q = query.toLowerCase().trim();
  return TECH_GENS.find(t => t.name.toLowerCase().includes(q))
    || TECH_GENS.find(t => q.includes(t.formFactor.toLowerCase()))
    || (() => {
      const m = q.match(/^(\d+(?:\.\d+)?)\s*(g|t)\b/i);
      if (m) {
        const gbps = m[2].toLowerCase() === "t" ? parseFloat(m[1]) * 1000 : parseFloat(m[1]);
        return TECH_GENS.find(t => t.speedGbps === gbps);
      }
      return undefined;
    })();
}

export async function registerKnowledgeTools(server: McpServer): Promise<void> {
  // --- Tool: search_knowledge_base ---
  server.tool(
    "search_knowledge_base",
    "Search troubleshooting guides, FAQs, and best practices. Use for diagnosing transceiver/switch issues.",
    {
      query: z.string().describe("Problem description or question, e.g. 'low Rx power QSFP28' or 'link flapping SFP+'"),
      category: z.enum(["troubleshooting", "faq", "best_practice", "configuration"]).optional(),
      severity: z.enum(["critical", "high", "medium", "low"]).optional().describe("Filter by issue severity"),
    },
    async ({ query, category, severity }) => {
      const conditions = [`kb.search_vector @@ plainto_tsquery('english', $1)`];
      const values: unknown[] = [query];
      let idx = 2;

      if (category) {
        conditions.push(`kb.category = $${idx}`);
        values.push(category);
        idx++;
      }
      if (severity) {
        conditions.push(`kb.severity = $${idx}`);
        values.push(severity);
        idx++;
      }

      const result = await pool.query(
        `SELECT kb.id, kb.title, kb.content, kb.category, kb.severity,
                kb.affected_products, kb.resolution, kb.source_url,
                ts_rank(kb.search_vector, plainto_tsquery('english', $1)) as rank
         FROM knowledge_base kb
         WHERE ${conditions.join(" AND ")}
         ORDER BY rank DESC
         LIMIT 10`,
        values
      );

      if (result.rows.length === 0) {
        return {
          content: [{
            type: "text",
            text: `No knowledge base entries found for: "${query}". Knowledge base grows as vendor FAQs are scraped.`,
          }],
        };
      }

      return {
        content: [{
          type: "text",
          text: JSON.stringify({ results: result.rows, count: result.rows.length }, null, 2),
        }],
      };
    }
  );

  // --- Tool: search_manuals ---
  server.tool(
    "search_manuals",
    "Search switch manuals, configuration guides, and compatibility lists. Returns relevant document excerpts.",
    {
      query: z.string().describe("Query, e.g. 'configure DWDM on Juniper MX' or 'QSFP28 installation guide'"),
      vendor: z.string().optional().describe("Document vendor filter, e.g. 'Cisco', 'Juniper', 'Arista'"),
      doc_type: z.enum(["manual", "config_guide", "compatibility_list", "datasheet", "release_notes"]).optional(),
    },
    async ({ query, vendor, doc_type }) => {
      const conditions = [`d.search_vector @@ plainto_tsquery('english', $1)`];
      const values: unknown[] = [query];
      let idx = 2;

      if (vendor) {
        conditions.push(`v.name ILIKE $${idx}`);
        values.push(`%${vendor}%`);
        idx++;
      }
      if (doc_type) {
        conditions.push(`d.doc_type = $${idx}`);
        values.push(doc_type);
        idx++;
      }

      const result = await pool.query(
        `SELECT d.id, d.title, d.doc_type, d.version,
                v.name as vendor, d.source_url, d.pages,
                d.summary,
                ts_rank(d.search_vector, plainto_tsquery('english', $1)) as rank
         FROM documents d
         LEFT JOIN vendors v ON v.id = d.vendor_id
         WHERE ${conditions.join(" AND ")}
         ORDER BY rank DESC
         LIMIT 10`,
        values
      );

      if (result.rows.length === 0) {
        return {
          content: [{
            type: "text",
            text: `No manuals found for: "${query}". Document library grows as manuals are processed by OCR pipeline.`,
          }],
        };
      }

      return {
        content: [{
          type: "text",
          text: JSON.stringify({ results: result.rows, count: result.rows.length }, null, 2),
        }],
      };
    }
  );

  // --- Tool: get_hype_cycle ---
  server.tool(
    "get_hype_cycle",
    "Get Hype Cycle position and Norton-Bass diffusion forecast for a transceiver technology. Shows market maturity, adoption phase, and price trajectory.",
    {
      technology: z.string().describe("Technology to analyze, e.g. '800G OSFP', 'CPO', '400ZR', '100G LR4', 'DWDM'"),
      include_forecast: z.boolean().default(true).describe("Include Norton-Bass 5-year adoption forecast"),
    },
    async ({ technology, include_forecast }) => {
      // Look for market metrics data
      const result = await pool.query(
        `SELECT mm.time, mm.metric_type, mm.value,
                mm.notes
         FROM market_metrics mm
         WHERE mm.technology ILIKE $1
            OR mm.notes ILIKE $1
         ORDER BY mm.time DESC
         LIMIT 50`,
        [`%${technology}%`]
      );

      // Also check news for recent developments
      const newsResult = await pool.query(
        `SELECT title, published_at, source, summary
         FROM news_articles
         WHERE search_vector @@ plainto_tsquery('english', $1)
            OR title ILIKE $2
         ORDER BY published_at DESC
         LIMIT 5`,
        [technology, `%${technology}%`]
      );

      // Norton-Bass Diffusion Model computation
      const currentYear = new Date().getFullYear();
      const tech = findTech(technology);

      let hypeData: Record<string, unknown> | null = null;
      let forecast: Record<string, unknown> | undefined = undefined;

      if (tech) {
        const t = Math.max(0, currentYear - tech.introYear);
        const yearsToPeak = tech.peakYear - tech.introYear;
        const progressRatio = t / yearsToPeak;
        const adoption = bassCumulative(t, tech.p, tech.q);
        const rate = bassRate(t, tech.p, tech.q);
        const phase = classifyHypePhase(progressRatio);

        // Position on curve (0-100) based on progress ratio
        const positionPct = Math.min(100, Math.round(
          progressRatio < 0.15 ? progressRatio / 0.15 * 15 :
          progressRatio < 0.35 ? 15 + (progressRatio - 0.15) / 0.20 * 15 :
          progressRatio < 0.55 ? 30 + (progressRatio - 0.35) / 0.20 * 20 :
          progressRatio < 0.85 ? 50 + (progressRatio - 0.55) / 0.30 * 30 :
          80 + Math.min(20, (progressRatio - 0.85) / 0.45 * 20)
        ));

        hypeData = {
          technology: tech.name,
          phase,
          position: positionPct,
          adoption_pct: Math.round(adoption * 100),
          yearly_adoption_rate: Math.round(rate * 100),
          intro_year: tech.introYear,
          peak_year: tech.peakYear,
          years_to_plateau: Math.max(0, tech.peakYear + 3 - currentYear),
          model: "Norton-Bass Multigenerational Diffusion",
          parameters: { p: tech.p, q: tech.q, m: tech.m, k: tech.k, t0: tech.t0 },
        };

        if (include_forecast) {
          const fiveYear = Array.from({ length: 5 }, (_, i) => {
            const yr = currentYear + i + 1;
            const ft = yr - tech.introYear;
            const fa = bassCumulative(ft, tech.p, tech.q);
            const pr = ft / yearsToPeak;
            return { year: yr, adoption_pct: Math.round(fa * 100), phase: classifyHypePhase(pr) };
          });

          const aspDecline = progressRatio < 0.3 ? 5 : progressRatio < 0.6 ? 35 : progressRatio < 1.0 ? 15 : 5;

          forecast = {
            model: "Norton-Bass Multigenerational Diffusion",
            current_adoption_pct: Math.round(adoption * 100),
            estimated_peak_year: tech.peakYear,
            years_to_plateau: Math.max(0, tech.peakYear + 3 - currentYear),
            asp_decline_rate_pct: aspDecline,
            price_trend: aspDecline > 20 ? "Rapidly declining" : aspDecline > 10 ? "Moderately declining" : "Stabilizing",
            five_year_projection: fiveYear,
          };
        }
      }

      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            technology,
            hype_cycle: hypeData || { note: `No model data for "${technology}". Known: 1G, 10G, 25G, 40G, 100G, 400G, 800G, 1.6T, CPO, LPO, 400ZR` },
            market_metrics: result.rows,
            recent_news: newsResult.rows,
            norton_bass_forecast: forecast,
          }, null, 2),
        }],
      };
    }
  );
}
