/**
 * MCP Tools API Route
 *
 * Proxies callServerTool requests from MCP App iframes to the appropriate
 * backend API (n8n, GHL, Google Ads, Meta Ads, etc.).
 *
 * Called by useMcpBridge when an iframe sends a tools/call JSON-RPC message.
 */
import { NextRequest, NextResponse } from "next/server";
import {
  readLeads,
  readDailyStats,
  readLogTail,
  startScrapeJob,
  getJob,
  listJobs,
  getSavedSearches,
  exportLeadsAsCsv,
  exportLeadsAsJson,
} from "@/lib/reonomy-service";

const N8N_API_URL = process.env.N8N_API_URL || "https://auto.localbosses.org";
const N8N_API_KEY = process.env.N8N_API_KEY || "";

// ─── n8n API helper ────────────────────────────────────
async function n8nApi(
  path: string,
  options: RequestInit = {}
): Promise<unknown> {
  const url = `${N8N_API_URL}/api/v1${path}`;
  const res = await fetch(url, {
    ...options,
    headers: {
      "X-N8N-API-KEY": N8N_API_KEY,
      "Content-Type": "application/json",
      ...(options.headers as Record<string, string>),
    },
  });

  if (!res.ok) {
    const text = await res.text().catch(() => "Unknown error");
    throw new Error(`n8n API error ${res.status}: ${text}`);
  }

  return res.json();
}

// ─── n8n tool handlers ─────────────────────────────────
async function handleN8nTool(
  name: string,
  args: Record<string, unknown>
): Promise<unknown> {
  switch (name) {
    // App-only tools (called from UI iframes)
    case "n8n_toggle_workflow": {
      const endpoint = args.active ? "activate" : "deactivate";
      return await n8nApi(`/workflows/${args.id}/${endpoint}`, {
        method: "POST",
      });
    }

    case "n8n_delete_workflow_action": {
      return await n8nApi(`/workflows/${args.id}`, { method: "DELETE" });
    }

    case "n8n_create_workflow_action": {
      const body = {
        name: args.name,
        nodes:
          typeof args.nodes === "string"
            ? JSON.parse(args.nodes as string)
            : args.nodes,
        connections:
          typeof args.connections === "string"
            ? JSON.parse(args.connections as string)
            : args.connections,
        settings: { executionOrder: "v1" },
      };
      return await n8nApi("/workflows", {
        method: "POST",
        body: JSON.stringify(body),
      });
    }

    // Data-fetching tools (used for pagination, refresh, etc.)
    case "n8n_workflow_dashboard": {
      const params = new URLSearchParams();
      if (args.active !== undefined) params.set("active", String(args.active));
      params.set("limit", String(args.limit || 100));
      return await n8nApi(`/workflows?${params}`);
    }

    case "n8n_workflow_detail": {
      return await n8nApi(`/workflows/${args.id}`);
    }

    case "n8n_execution_dashboard": {
      const params = new URLSearchParams();
      if (args.workflowId)
        params.set("workflowId", String(args.workflowId));
      if (args.status) params.set("status", String(args.status));
      if (args.cursor) params.set("cursor", String(args.cursor));
      params.set("limit", String(args.limit || 50));
      return await n8nApi(`/executions?${params}`);
    }

    case "n8n_health_monitor": {
      try {
        const users = await n8nApi("/users");
        return {
          mode: args.mode || "status",
          health: {
            connected: true,
            users:
              (users as { data?: unknown[] })?.data?.length || 0,
            apiUrl: N8N_API_URL,
          },
          timestamp: new Date().toISOString(),
        };
      } catch (e: unknown) {
        const message =
          e instanceof Error ? e.message : "Unknown error";
        return {
          mode: args.mode || "status",
          health: { connected: false, error: message },
          timestamp: new Date().toISOString(),
        };
      }
    }

    case "n8n_test_workflow": {
      const workflow = await n8nApi(`/workflows/${args.workflowId}`);
      return {
        workflow,
        triggerType: args.triggerType || "webhook",
        testData: args.data || {},
      };
    }

    case "n8n_search_nodes": {
      // Node search is client-side in the app; return empty acknowledgment
      return { action: "search", query: args.query || "" };
    }

    default:
      throw new Error(`Unknown n8n tool: ${name}`);
  }
}

// ─── Reonomy tool handlers ──────────────────────────────
// Real bridge to Reonomy scraper v13 (Puppeteer + agent-browser)

async function handleReonomyTool(
  name: string,
  args: Record<string, unknown>
): Promise<unknown> {
  switch (name) {
    case "reonomy_get_filters": {
      // Return available search configurations + saved searches
      const searches = getSavedSearches();
      const stats = readDailyStats();
      return {
        savedSearches: searches,
        dailyStats: stats,
        dailyLimit: 50,
        remainingToday: 50 - stats.propertiesScraped,
        filters: {
          location: { type: "text", label: "Location", placeholder: "City, State, or ZIP" },
          propertyTypes: {
            type: "multi-select",
            label: "Property Type",
            options: ["Office", "Retail", "Industrial", "Multifamily", "Hotel", "Land", "Mixed Use", "Special Purpose"],
          },
          contactFilters: {
            type: "multi-select",
            label: "Contact Availability",
            options: ["Has Phone", "Has Email", "Portfolio 2+"],
          },
        },
        note: "Searches are configured on Reonomy's web UI with filters, then saved with their search ID. Use saved search IDs for scraping.",
      };
    }

    case "reonomy_search": {
      // Return saved searches matching query + current state
      const location = (args.location as string) || "";
      const searches = getSavedSearches();
      const stats = readDailyStats();
      const leads = readLeads();

      return {
        savedSearches: searches,
        currentLeads: leads?.totalLeads || 0,
        lastUpdated: leads?.lastUpdated || null,
        dailyStats: stats,
        remainingToday: 50 - stats.propertiesScraped,
        message: location
          ? `To search "${location}", configure filters on Reonomy's web UI first, then save the search ID. Or use an existing saved search to scrape.`
          : "Use a saved search ID with reonomy_scrape to start extracting leads.",
      };
    }

    case "reonomy_scrape": {
      // START a real scrape job using the Puppeteer scraper
      const searchId = (args.searchId as string) || undefined;
      const maxProperties = (args.maxProperties as number) || (args.limit as number) || 10;

      const job = startScrapeJob({ searchId, maxProperties });

      return {
        jobId: job.id,
        status: job.status,
        searchId: job.searchId,
        maxProperties: job.maxProperties,
        startedAt: job.startedAt,
        error: job.error || null,
        message: job.status === "running"
          ? `Scrape started! Extracting up to ${maxProperties} properties. This takes 30-60 seconds per property. Use reonomy_get_results to check progress.`
          : `Scrape failed: ${job.error}`,
      };
    }

    case "reonomy_scrape_status": {
      // Check status of a running scrape job
      const jobId = args.jobId as string;
      if (jobId) {
        const job = getJob(jobId);
        if (!job) return { error: `Job ${jobId} not found` };
        return job;
      }
      // Return all jobs
      return { jobs: listJobs() };
    }

    case "reonomy_get_results": {
      // Return REAL scraped leads from the leads file
      const page = (args.page as number) || 1;
      const perPage = (args.perPage as number) || 20;
      const stateFilter = (args.state as string) || null;
      const typeFilter = (args.propertyType as string) || null;

      const data = readLeads();
      if (!data || data.leads.length === 0) {
        return {
          totalResults: 0,
          page,
          perPage,
          leads: [],
          dailyStats: readDailyStats(),
          message: "No leads scraped yet. Use reonomy_scrape to start extracting from Reonomy.",
        };
      }

      // Filter
      let filtered = data.leads;
      if (stateFilter) {
        filtered = filtered.filter(
          (l) => l.state?.toLowerCase() === stateFilter.toLowerCase()
        );
      }
      if (typeFilter) {
        filtered = filtered.filter(
          (l) => l.propertyType?.toLowerCase().includes(typeFilter.toLowerCase())
        );
      }

      // Paginate
      const start = (page - 1) * perPage;
      const pageLeads = filtered.slice(start, start + perPage);
      const totalPages = Math.ceil(filtered.length / perPage);

      return {
        totalResults: filtered.length,
        page,
        perPage,
        totalPages,
        lastUpdated: data.lastUpdated,
        searchId: data.searchId,
        dailyStats: readDailyStats(),
        leads: pageLeads,
      };
    }

    case "reonomy_export": {
      const format = (args.format as string) || "csv";
      const data = readLeads();

      if (!data || data.leads.length === 0) {
        return { error: "No leads to export. Run a scrape first." };
      }

      const exported = format === "json"
        ? exportLeadsAsJson(data.leads)
        : exportLeadsAsCsv(data.leads);

      return {
        format,
        recordCount: data.leads.length,
        filename: `reonomy-leads-${new Date().toISOString().slice(0, 10)}.${format}`,
        data: exported,
        message: `Exported ${data.leads.length} leads as ${format.toUpperCase()}.`,
      };
    }

    case "reonomy_dashboard": {
      // Aggregate stats for the dashboard app
      const data = readLeads();
      const stats = readDailyStats();
      const jobs = listJobs();
      const leads = data?.leads || [];

      // Compute stats
      const totalOwners = leads.reduce((sum, l) => sum + l.owners.length, 0);
      const totalPhones = leads.reduce(
        (sum, l) => sum + l.owners.reduce((s, o) => s + o.phones.length, 0), 0
      );
      const totalEmails = leads.reduce(
        (sum, l) => sum + l.owners.reduce((s, o) => s + o.emails.length, 0), 0
      );

      // State breakdown
      const byState: Record<string, number> = {};
      for (const lead of leads) {
        const st = lead.state || "Unknown";
        byState[st] = (byState[st] || 0) + 1;
      }

      // Type breakdown
      const byType: Record<string, number> = {};
      for (const lead of leads) {
        const t = lead.propertyType || "Unknown";
        byType[t] = (byType[t] || 0) + 1;
      }

      return {
        totalLeads: leads.length,
        totalOwners,
        totalPhones,
        totalEmails,
        lastUpdated: data?.lastUpdated || null,
        dailyStats: stats,
        remainingToday: 50 - stats.propertiesScraped,
        byState,
        byType,
        recentLeads: leads.slice(-5).reverse(),
        recentJobs: jobs.slice(-5).reverse(),
        savedSearches: getSavedSearches(),
        logTail: readLogTail(15),
      };
    }

    default:
      throw new Error(`Unknown Reonomy tool: ${name}`);
  }
}

// ─── Route handler ─────────────────────────────────────
export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const { tool, arguments: args } = body as {
      tool?: string;
      arguments?: Record<string, unknown>;
      server?: string;
    };

    if (!tool) {
      return NextResponse.json(
        { error: "Missing tool name" },
        { status: 400 }
      );
    }

    let result: unknown;

    // Route based on tool name prefix
    if (tool.startsWith("n8n_")) {
      if (!N8N_API_KEY) {
        return NextResponse.json(
          {
            content: [
              {
                type: "text",
                text: JSON.stringify({
                  error: "N8N_API_KEY not configured",
                }),
              },
            ],
            isError: true,
          },
          { status: 500 }
        );
      }
      result = await handleN8nTool(tool, args || {});
    } else if (tool.startsWith("ghl_")) {
      // TODO: GHL API handler
      return NextResponse.json(
        {
          content: [
            {
              type: "text",
              text: JSON.stringify({
                error: "GHL tools not yet implemented",
              }),
            },
          ],
          isError: true,
        },
        { status: 501 }
      );
    } else if (tool.startsWith("google_ads_")) {
      // TODO: Google Ads API handler
      return NextResponse.json(
        {
          content: [
            {
              type: "text",
              text: JSON.stringify({
                error: "Google Ads tools not yet implemented",
              }),
            },
          ],
          isError: true,
        },
        { status: 501 }
      );
    } else if (tool.startsWith("meta_ads_")) {
      // TODO: Meta Ads API handler
      return NextResponse.json(
        {
          content: [
            {
              type: "text",
              text: JSON.stringify({
                error: "Meta Ads tools not yet implemented",
              }),
            },
          ],
          isError: true,
        },
        { status: 501 }
      );
    } else if (tool.startsWith("reonomy_")) {
      result = await handleReonomyTool(tool, args || {});
    } else {
      return NextResponse.json(
        {
          content: [
            {
              type: "text",
              text: JSON.stringify({
                error: `Unknown tool prefix for: ${tool}`,
              }),
            },
          ],
          isError: true,
        },
        { status: 400 }
      );
    }

    // Return in MCP-compatible format
    return NextResponse.json({
      content: [
        {
          type: "text",
          text:
            typeof result === "string" ? result : JSON.stringify(result),
        },
      ],
    });
  } catch (error) {
    const message =
      error instanceof Error ? error.message : "Internal server error";
    return NextResponse.json(
      {
        content: [{ type: "text", text: JSON.stringify({ error: message }) }],
        isError: true,
      },
      { status: 500 }
    );
  }
}
