/**
 * QR Rápido MCP Server (Node.js — test/dev)
 *
 * Variáveis de ambiente:
 *   QR_API_KEY  — sua API key (ex: qr_xxxx)
 *   QR_BASE_URL — base URL da API (default: https://qrrapido.site)
 *   NODE_TLS_REJECT_UNAUTHORIZED=0  — necessário para localhost com cert self-signed
 */

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { fetch } from "undici";
import { writeFileSync } from "fs";
import { tmpdir } from "os";
import { join } from "path";
import { exec } from "child_process";

const API_KEY  = process.env.QR_API_KEY  || "";
const BASE_URL = process.env.QR_BASE_URL || "https://qrrapido.site";

if (!API_KEY) process.stderr.write("[qrrapido-mcp] AVISO: QR_API_KEY não definida\n");

// ── PIX EMV/BRCode builder (port do C# em PagamentoController) ────────────────

function pixField(id, value) {
  const len = String(value.length).padStart(2, "0");
  return `${id}${len}${value}`;
}

function removeAccents(text) {
  return text.toUpperCase()
    .normalize("NFD").replace(/[\u0300-\u036f]/g, "")
    .replace(/[^A-Z0-9 ]/g, " ");
}

function crc16(data) {
  let crc = 0xFFFF;
  for (const ch of data) {
    crc ^= ch.charCodeAt(0) << 8;
    for (let i = 0; i < 8; i++) {
      crc = (crc & 0x8000) ? ((crc << 1) ^ 0x1021) & 0xFFFF : (crc << 1) & 0xFFFF;
    }
  }
  return crc.toString(16).toUpperCase().padStart(4, "0");
}

function buildPixPayload({ pixKey, amount, merchantName, merchantCity, txId = "***" }) {
  const merchantInfo = pixField("00", "br.gov.bcb.pix") + pixField("01", pixKey);
  const addData = pixField("05", txId.substring(0, 25));
  const name = removeAccents(merchantName).substring(0, 25);
  const city = removeAccents(merchantCity).substring(0, 15);

  let payload = pixField("00", "01")
    + pixField("26", merchantInfo)
    + pixField("52", "0000")
    + pixField("53", "986");

  if (amount && amount > 0) {
    payload += pixField("54", amount.toFixed(2));
  }

  payload += pixField("58", "BR")
    + pixField("59", name)
    + pixField("60", city)
    + pixField("62", addData)
    + "6304";

  return payload + crc16(payload);
}

// ── API helper ────────────────────────────────────────────────────────────────

async function callApi(body) {
  const res = await fetch(`${BASE_URL}/api/v1/QRManager/generate`, {
    method: "POST",
    headers: { "X-API-Key": API_KEY, "Content-Type": "application/json" },
    body: JSON.stringify(body)
  });
  return res.json();
}

function errorContent(msg) {
  return { content: [{ type: "text", text: `❌ ${msg}` }], isError: true };
}

function openImage(base64, label = "qr") {
  try {
    const ext = "png";
    const file = join(tmpdir(), `${label}_${Date.now()}.${ext}`);
    writeFileSync(file, Buffer.from(base64, "base64"));
    exec(`start "" "${file}"`);
    return file;
  } catch (e) {
    process.stderr.write(`[qrrapido-mcp] Não abriu imagem: ${e.message}\n`);
    return null;
  }
}

function successContent(data, label = "qr") {
  const file = openImage(data.qrCodeBase64, label);
  return {
    content: [
      { type: "image", data: data.qrCodeBase64, mimeType: data.mimeType || "image/png" },
      {
        type: "text",
        text: [
          `✅ QR code gerado`,
          file ? `🖼  Aberto em: ${file}` : "",
          `⏱  ${data.generationTimeMs}ms`,
          `💾 Cache: ${data.fromCache ? "hit" : "miss"}`,
          `📊 Créditos restantes: ${data.remainingCredits ?? "N/A"}`
        ].filter(Boolean).join("\n")
      }
    ]
  };
}

// ── Server ────────────────────────────────────────────────────────────────────

const server = new Server(
  { name: "qrrapido", version: "0.2.0" },
  { capabilities: { tools: {} } }
);

// tools/list
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: "generate_qr",
      description:
        "Gera QR code para URL, Wi-Fi, vCard, WhatsApp, Email, SMS ou texto livre. " +
        "Para PIX use generate_pix_qr.",
      inputSchema: {
        type: "object",
        properties: {
          type: {
            type: "string",
            enum: ["url", "wifi", "vcard", "whatsapp", "email", "sms", "texto"],
            description: "Tipo do QR code"
          },
          content: { type: "string", description: "Conteúdo do QR code" },
          format: { type: "string", enum: ["png", "webp", "svg"], default: "png" },
          size: { type: "number", default: 400, description: "Tamanho em pixels (100–2000)" },
          primaryColor: { type: "string", default: "#000000", description: "Cor hex do QR" },
          backgroundColor: { type: "string", default: "#FFFFFF", description: "Cor hex de fundo" }
        },
        required: ["type", "content"]
      }
    },
    {
      name: "generate_pix_qr",
      description:
        "Gera QR code PIX (BRCode/EMV) para recebimento de pagamento. " +
        "Monte o payload automaticamente com chave, valor, nome e cidade.",
      inputSchema: {
        type: "object",
        properties: {
          pixKey: {
            type: "string",
            description: "Chave PIX: CPF (somente dígitos), email, telefone (+5511...) ou chave aleatória"
          },
          amount: {
            type: "number",
            description: "Valor em reais (ex: 50.00). Omita para QR de valor aberto."
          },
          merchantName: {
            type: "string",
            description: "Nome do recebedor (max 25 chars, ex: RICARDO CARNEIRO)"
          },
          merchantCity: {
            type: "string",
            description: "Cidade do recebedor (max 15 chars, ex: SAO PAULO)"
          },
          txId: {
            type: "string",
            default: "***",
            description: "ID da transação (opcional, max 25 chars)"
          },
          size: { type: "number", default: 400, description: "Tamanho em pixels" },
          primaryColor: { type: "string", default: "#000000" },
          backgroundColor: { type: "string", default: "#FFFFFF" }
        },
        required: ["pixKey", "merchantName", "merchantCity"]
      }
    }
  ]
}));

// tools/call
server.setRequestHandler(CallToolRequestSchema, async (req) => {
  const { name } = req.params;
  const args = req.params.arguments ?? {};

  // ── generate_pix_qr ──────────────────────────────────────────────────────
  if (name === "generate_pix_qr") {
    const { pixKey, amount, merchantName, merchantCity, txId = "***",
            size = 400, primaryColor = "#000000", backgroundColor = "#FFFFFF" } = args;

    if (!pixKey || !merchantName || !merchantCity)
      return errorContent("pixKey, merchantName e merchantCity são obrigatórios.");

    let payload;
    try {
      payload = buildPixPayload({ pixKey, amount, merchantName, merchantCity, txId });
    } catch (err) {
      return errorContent(`Erro ao montar payload PIX: ${err.message}`);
    }

    let data;
    try {
      data = await callApi({ type: "texto", content: payload, size, primaryColor, backgroundColor });
    } catch (err) {
      return errorContent(`Falha na requisição: ${err.message}`);
    }

    if (!data.success) return errorContent(data.message || data.error || "Erro desconhecido");

    const pixFile = openImage(data.qrCodeBase64, "pix");
    return {
      content: [
        { type: "image", data: data.qrCodeBase64, mimeType: data.mimeType || "image/png" },
        {
          type: "text",
          text: [
            `✅ QR code PIX gerado`,
            pixFile ? `🖼  Aberto em: ${pixFile}` : "",
            `🔑 Chave: ${pixKey}`,
            `💰 Valor: ${amount ? `R$ ${amount.toFixed(2)}` : "aberto"}`,
            `👤 Recebedor: ${merchantName} — ${merchantCity}`,
            `⏱  ${data.generationTimeMs}ms`
          ].filter(Boolean).join("\n")
        }
      ]
    };
  }

  // ── generate_qr ──────────────────────────────────────────────────────────
  if (name === "generate_qr") {
    const { type, content, format = "png", size = 400,
            primaryColor = "#000000", backgroundColor = "#FFFFFF" } = args;

    if (!type || !content) return errorContent("'type' e 'content' são obrigatórios.");

    let data;
    try {
      data = await callApi({ type, content, outputFormat: format, size, primaryColor, backgroundColor });
    } catch (err) {
      return errorContent(`Falha na requisição: ${err.message}`);
    }

    if (!data.success) return errorContent(data.message || data.error || "Erro desconhecido");
    return successContent(data);
  }

  return errorContent(`Tool desconhecida: ${name}`);
});

// ── Start ─────────────────────────────────────────────────────────────────────

const transport = new StdioServerTransport();
await server.connect(transport);
process.stderr.write(`[qrrapido-mcp] Servidor iniciado. Base URL: ${BASE_URL}\n`);
