"use client";

/**
 * ConceptExportButtons — export controls for one concept variant.
 *
 * The Stage-1a backend contract (`backend/app/api/v1/concepts.py`) ships only
 * `POST /concepts`; no export endpoint exists yet. So:
 *   - GeoJSON (buildings) + CSV (ТЭП + финмодель) are generated client-side
 *     here, re-using `triggerDownload` and the CSV-injection-safe escaping from
 *     the Site Finder ExportButtons.
 *   - DXF / PDF are produced server-side (ezdxf / WeasyPrint per the stack).
 *     We POST the variant to the documented `/api/v1/concepts/export` path and
 *     download the blob; until that endpoint lands the button reports a clear
 *     "не готово" message instead of failing silently.
 */

import { useState } from "react";
import { Download, FileCode, FileText, Map as MapIcon } from "lucide-react";

import { API_BASE_URL } from "@/lib/api";
import { triggerDownload } from "@/lib/download";
import { STRATEGY_LABELS, type ConceptVariant } from "@/lib/concept-api";

// ── CSV helpers (mirrors site-finder ExportButtons) ───────────────────────────

function escapeCsvCell(cell: string): string {
  // CSV-injection mitigation (OWASP / CWE-1236): cells starting with =, +, -, @,
  // tab, or CR are evaluated as formulas by Excel/Calc/Sheets. Prefix dangerous
  // starters with a leading apostrophe so the spreadsheet treats them as text.
  let safe = cell;
  if (/^[=+\-@\t\r]/.test(safe)) {
    safe = "'" + safe;
  }
  const needsQuotes = /[",\n\r]/.test(safe);
  if (needsQuotes) {
    return `"${safe.replace(/"/g, '""')}"`;
  }
  return safe;
}

function buildCsvRows(variant: ConceptVariant): string[][] {
  const t = variant.teap;
  const f = variant.financial;
  return [
    ["Показатель", "Значение"],
    ["Стратегия", STRATEGY_LABELS[variant.strategy]],
    ["Площадь застройки, м²", String(t.built_area_sqm)],
    ["Общая площадь, м²", String(t.total_floor_area_sqm)],
    ["Жилая площадь, м²", String(t.residential_area_sqm)],
    ["Квартир, шт", String(t.apartments_count)],
    ["Плотность", String(t.density)],
    ["Машино-мест", String(t.parking_spaces)],
    ["Выручка, ₽", String(f.revenue_rub)],
    ["Затраты, ₽", String(f.cost_rub)],
    ["Валовая прибыль, ₽", String(f.gross_margin_rub)],
    ["IRR", String(f.irr)],
  ];
}

function generateCsvBlob(rows: string[][]): Blob {
  const csv = rows.map((row) => row.map(escapeCsvCell).join(",")).join("\r\n");
  // UTF-8 BOM so Excel renders Cyrillic correctly.
  return new Blob(["﻿" + csv], { type: "text/csv;charset=utf-8" });
}

// ── Component ─────────────────────────────────────────────────────────────────

const today = () => new Date().toISOString().slice(0, 10);

interface Props {
  variant: ConceptVariant;
}

export function ConceptExportButtons({ variant }: Props) {
  const [serverLoading, setServerLoading] = useState<"dxf" | "pdf" | null>(
    null,
  );
  const [error, setError] = useState<string | null>(null);

  const fileStem = `gendesign_concept_${variant.strategy}_${today()}`;

  function handleGeojson() {
    setError(null);
    const blob = new Blob(
      [JSON.stringify(variant.buildings_geojson, null, 2)],
      {
        type: "application/geo+json",
      },
    );
    triggerDownload(blob, `${fileStem}.geojson`);
  }

  function handleCsv() {
    setError(null);
    const blob = generateCsvBlob(buildCsvRows(variant));
    triggerDownload(blob, `${fileStem}.csv`);
  }

  async function handleServerExport(format: "dxf" | "pdf") {
    setServerLoading(format);
    setError(null);
    try {
      const res = await fetch(
        `${API_BASE_URL}/api/v1/concepts/export?format=${format}`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(variant),
        },
      );
      if (res.status === 404 || res.status === 405) {
        setError(
          format === "dxf"
            ? "Экспорт DXF появится после публикации движка генерации."
            : "Экспорт PDF появится после публикации движка генерации.",
        );
        return;
      }
      if (!res.ok) {
        throw new Error(`Ошибка сервера ${res.status}`);
      }
      const blob = await res.blob();
      triggerDownload(blob, `${fileStem}.${format}`);
    } catch (err) {
      const msg =
        err instanceof Error
          ? err.message
          : `Ошибка экспорта ${format.toUpperCase()}`;
      setError(msg);
    } finally {
      setServerLoading(null);
    }
  }

  const secondaryBtn: React.CSSProperties = {
    display: "inline-flex",
    alignItems: "center",
    gap: 6,
    padding: "6px 12px",
    height: 32,
    background: "var(--accent-2)",
    color: "#fff",
    border: "none",
    borderRadius: 6,
    fontSize: 13,
    fontWeight: 500,
    cursor: "pointer",
  };

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
        <button
          type="button"
          onClick={handleGeojson}
          aria-label="Скачать геометрию зданий GeoJSON"
          style={secondaryBtn}
        >
          <MapIcon size={14} strokeWidth={1.5} />
          GeoJSON
        </button>
        <button
          type="button"
          onClick={handleCsv}
          aria-label="Скачать ТЭП и финмодель CSV"
          style={secondaryBtn}
        >
          <Download size={14} strokeWidth={1.5} />
          CSV
        </button>
        <button
          type="button"
          onClick={() => void handleServerExport("dxf")}
          disabled={serverLoading !== null}
          aria-label="Скачать DXF"
          style={{
            ...secondaryBtn,
            opacity: serverLoading !== null ? 0.6 : 1,
            cursor: serverLoading !== null ? "not-allowed" : "pointer",
          }}
        >
          <FileCode size={14} strokeWidth={1.5} />
          {serverLoading === "dxf" ? "Экспорт…" : "DXF"}
        </button>
        <button
          type="button"
          onClick={() => void handleServerExport("pdf")}
          disabled={serverLoading !== null}
          aria-label="Скачать PDF"
          style={{
            ...secondaryBtn,
            opacity: serverLoading !== null ? 0.6 : 1,
            cursor: serverLoading !== null ? "not-allowed" : "pointer",
          }}
        >
          <FileText size={14} strokeWidth={1.5} />
          {serverLoading === "pdf" ? "Экспорт…" : "PDF"}
        </button>
      </div>
      {error && (
        <p
          style={{ margin: 0, fontSize: 12, color: "var(--warn)" }}
          role="status"
        >
          {error}
        </p>
      )}
    </div>
  );
}
