import { useRef, forwardRef, useImperativeHandle, useState } from "react";
import { uploadToBackend } from "../lib/api";
import { showToast } from "../lib/toast";

// Human-readable labels for canonical Signal field names.
const FIELD_LABELS = {
  patient_id: "Patient ID",
  device_type: "Device Type",
  shipment_date: "Shipment Date",
  quantity: "Quantity",
  payer: "Payer",
  plan_type: "Plan Type",
  component: "Component",
  csv_visit_date: "Visit Date",
  csv_swo_status: "SWO Status",
  csv_pecos_verified: "PECOS Verified",
  csv_pa_status: "PA Status",
  csv_diagnosis_on_file: "Diagnosis on File",
  csv_transfer_from: "Transfer From",
};

// Options available in the Override dropdown.
const OVERRIDE_OPTIONS = [
  { value: "patient_id", label: "Patient ID" },
  { value: "device_type", label: "Device Type" },
  { value: "shipment_date", label: "Shipment Date" },
  { value: "quantity", label: "Quantity" },
  { value: "payer", label: "Payer" },
  { value: "plan_type", label: "Plan Type" },
  { value: "skip", label: "Skip this column" },
];

// Map a backend confidence string to a short display label.
function confidenceLabel(confidence) {
  if (confidence === "high") return "Confident";
  if (confidence === "inferred") return "Check this";
  return "Uncertain";
}

function confidenceColor(confidence) {
  if (confidence === "high") return "text-[#1A8B5A]";
  if (confidence === "inferred") return "text-[var(--accent-text)]";
  return "text-[#CC6600]";
}

// Build the rows for the mapping review table from mapping_summary.
// Returns an array of row objects sorted so lower-confidence rows appear first.
function buildMappingRows(mappingSummary) {
  if (!mappingSummary?.mapped) return [];

  const rows = Object.entries(mappingSummary.mapped).map(([canonical, detail]) => ({
    canonical,
    rawHeader: detail.raw_header,
    confidence: detail.confidence,
    exampleValue: detail.example_value ?? null,
    override: canonical, // default to detected value
  }));

  // Sort: uncertain first, then inferred, then high confidence
  const order = { unmapped: 0, inferred: 1, high: 2 };
  rows.sort((a, b) => (order[a.confidence] ?? 0) - (order[b.confidence] ?? 0));

  return rows;
}

// Check whether mapping review should be shown (at least one mapped column present).
function shouldShowReview(mappingSummary) {
  return (
    mappingSummary &&
    mappingSummary.mapped &&
    Object.keys(mappingSummary.mapped).length > 0
  );
}

// Check whether any confidence scores are present in the mapping data.
function hasConfidenceData(rows) {
  return rows.some((r) => r.confidence && r.confidence !== "unmapped");
}

// ---- Main component ----

const CSVImport = forwardRef(function CSVImport({ onResults, getToken }, ref) {
  const inputRef = useRef(null);

  // Pending state while waiting for backend response.
  const [uploading, setUploading] = useState(false);

  // Mapping review state.
  const [reviewState, setReviewState] = useState(null);
  // reviewState shape: { rows, backendData, file }

  useImperativeHandle(ref, () => ({
    trigger: () => inputRef.current?.click(),
    uploadFile: async (file) => {
      if (!file) return;
      setUploading(true);
      try {
        const token = getToken ? await getToken().catch(() => null) : null;
        const data = await uploadToBackend(file, token);
        if (data && shouldShowReview(data.mapping_summary)) {
          const rows = buildMappingRows(data.mapping_summary);
          setReviewState({ rows, backendData: data, file });
          return;
        }
        onResults(data, file);
      } catch (err) {
        const m = /failed to fetch/i.test(String(err.message))
          ? "Can't reach the Signal server. Check you're on the official URL."
          : /401/.test(String(err.message))
            ? "Your session has expired — please sign in again."
            : `Upload failed: ${err.message}`;
        showToast(m);
      } finally {
        setUploading(false);
      }
    },
  }));

  const handleFile = async (e) => {
    const file = e.target.files?.[0];
    if (!file) return;
    e.target.value = "";

    setUploading(true);
    try {
      const token = getToken ? await getToken().catch(() => null) : null;
      const data = await uploadToBackend(file, token);

      if (data && shouldShowReview(data.mapping_summary)) {
        // Build review rows from the mapping summary.
        const rows = buildMappingRows(data.mapping_summary);
        setReviewState({ rows, backendData: data, file });
        return; // Hold here; user confirms or cancels.
      }

      onResults(data, file);
    } catch (err) {
      const m = /failed to fetch/i.test(String(err.message))
        ? "Can't reach the Signal server. Check you're on the official URL."
        : /401/.test(String(err.message))
          ? "Your session has expired — please sign in again."
          : `Upload failed: ${err.message}`;
      showToast(m);
    } finally {
      setUploading(false);
    }
  };

  const handleConfirm = () => {
    if (!reviewState) return;
    // Pass backend data through. Overrides are informational for now;
    // the worklist uses the backend's already-scored records.
    onResults(reviewState.backendData, reviewState.file);
    setReviewState(null);
  };

  const handleCancel = () => {
    setReviewState(null);
  };

  const handleOverrideChange = (index, newValue) => {
    setReviewState((prev) => {
      const rows = prev.rows.map((r, i) =>
        i === index ? { ...r, override: newValue } : r
      );
      return { ...prev, rows };
    });
  };

  const showConfidence = reviewState
    ? hasConfidenceData(reviewState.rows)
    : false;

  return (
    <>
      <input
        ref={inputRef}
        type="file"
        accept=".csv"
        onChange={handleFile}
        className="hidden"
      />

      {/* Uploading indicator — rendered off-screen, no visible flash for fast responses */}
      {uploading && !reviewState && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/20">
          <div className="bg-[var(--bg-card)] border border-[var(--border-color)] rounded-[10px] px-6 py-4 text-[13px] text-[var(--text-secondary)] shadow-lg">
            Reading your file...
          </div>
        </div>
      )}

      {/* Mapping review overlay */}
      {reviewState && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4">
          <div
            className="bg-[var(--bg-card)] border border-[var(--border-color)] rounded-[12px] shadow-xl w-full max-w-[780px] max-h-[90vh] flex flex-col"
            onClick={(e) => e.stopPropagation()}
          >
            {/* Header */}
            <div className="px-6 pt-6 pb-4 border-b border-[var(--border-color)]">
              <div className="font-heading font-bold text-[15px] text-[var(--text-heading)]">
                Review how your columns were mapped
              </div>
              <div className="text-[12px] text-[var(--text-warm)] mt-1">
                Signal matched your CSV headers to the fields it needs. Take a look
                before continuing, and use the Override column to correct anything
                that looks off.
              </div>
            </div>

            {/* Table */}
            <div className="overflow-auto flex-1 px-6 py-4">
              <table className="w-full text-[12px] border-collapse">
                <thead>
                  <tr className="border-b border-[var(--border-color)]">
                    <th className="text-left py-2 pr-4 font-semibold text-[var(--text-secondary)] whitespace-nowrap">
                      Original CSV header
                    </th>
                    <th className="text-left py-2 pr-4 font-semibold text-[var(--text-secondary)] whitespace-nowrap">
                      Detected Signal field
                    </th>
                    {reviewState.rows.some((r) => r.exampleValue !== null) && (
                      <th className="text-left py-2 pr-4 font-semibold text-[var(--text-secondary)] whitespace-nowrap">
                        Example value
                      </th>
                    )}
                    <th className="text-left py-2 font-semibold text-[var(--text-secondary)] whitespace-nowrap">
                      Override
                    </th>
                  </tr>
                </thead>
                <tbody>
                  {reviewState.rows.map((row, i) => (
                    <tr
                      key={i}
                      className="border-b border-[var(--border-color)] last:border-b-0 hover:bg-[var(--bg-elevated)]"
                    >
                      {/* Original CSV header */}
                      <td className="py-2 pr-4 font-mono text-[var(--text-primary)]">
                        {row.rawHeader}
                      </td>

                      {/* Detected Signal field */}
                      <td className="py-2 pr-4 text-[var(--text-secondary)]">
                        {FIELD_LABELS[row.canonical] ?? row.canonical}
                      </td>

                      {/* Example value */}
                      {reviewState.rows.some((r) => r.exampleValue !== null) && (
                        <td className="py-2 pr-4 font-mono text-[var(--text-warm)]">
                          {row.exampleValue ?? ""}
                        </td>
                      )}

                      {/* Override dropdown */}
                      <td className="py-2">
                        <select
                          value={row.override}
                          onChange={(e) => handleOverrideChange(i, e.target.value)}
                          className="border border-[var(--border-color)] rounded-[5px] px-2 py-1 text-[11px] bg-[var(--bg-elevated)] text-[var(--text-primary)] focus:outline-none focus:border-[var(--brand)] cursor-pointer"
                        >
                          {OVERRIDE_OPTIONS.map((opt) => (
                            <option key={opt.value} value={opt.value}>
                              {opt.label}
                            </option>
                          ))}
                        </select>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>

              {/* Unmapped columns notice */}
              {reviewState.backendData.mapping_summary.unmapped_columns?.length > 0 && (
                <div className="mt-4 text-[11px] text-[var(--text-warm)]">
                  <span className="font-semibold text-[var(--text-secondary)]">
                    Columns Signal did not use:
                  </span>{" "}
                  {reviewState.backendData.mapping_summary.unmapped_columns.join(", ")}
                </div>
              )}

              {/* Required missing notice */}
              {reviewState.backendData.mapping_summary.required_missing?.length > 0 && (
                <div className="mt-2 text-[11px] text-[#CC4400] bg-[#FFF4EE] border border-[#FFCFB0] rounded px-3 py-2">
                  Some required columns were not found:{" "}
                  {reviewState.backendData.mapping_summary.required_missing
                    .map((f) => FIELD_LABELS[f] ?? f)
                    .join(", ")}
                  . Check that your CSV includes these fields.
                </div>
              )}
            </div>

            {/* Footer actions */}
            <div className="px-6 py-4 border-t border-[var(--border-color)] flex items-center justify-between">
              <button
                onClick={handleCancel}
                className="text-[12px] text-[var(--text-warm)] hover:text-[var(--text-secondary)] underline cursor-pointer"
              >
                Cancel
              </button>
              <button
                onClick={handleConfirm}
                className="px-5 py-2 text-[12px] rounded-md bg-[var(--brand)] text-white font-semibold hover:opacity-90 cursor-pointer"
              >
                Looks good, continue
              </button>
            </div>
          </div>
        </div>
      )}
    </>
  );
});

export default CSVImport;
