/* global React, Icon */
const { useState, useEffect } = React;

// ── Sprint context widget (shown in check-in modal) ─────────────────────────
// Shows the user's assigned ADO items for the current sprint as lightweight
// context. Collapsible, loads lazily when the check-in modal opens.

function SprintContext({ authToken }) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [expanded, setExpanded] = useState(false);
  const [error, setError] = useState(null);
  const apiBase = window.PULSE_CONFIG?.apiBase || "http://localhost:8000";

  useEffect(() => {
    if (!authToken) return;
    fetch(`${apiBase}/ado/my-items`, {
      headers: { Authorization: `Bearer ${authToken}` },
    })
      .then((r) => {
        if (r.status === 404) return null; // no ADO connection
        if (!r.ok) throw new Error("Failed");
        return r.json();
      })
      .then((d) => {
        setData(d);
        setLoading(false);
      })
      .catch(() => {
        setError(true);
        setLoading(false);
      });
  }, [authToken]);

  // Don't render anything if no ADO connection or error
  if (loading || error || !data || !data.items || data.items.length === 0)
    return null;

  const STATE_CSS = {
    New: "new",
    Approved: "approved",
    Committed: "committed",
    Active: "active",
    Done: "done",
  };

  const TYPE_ICON = {
    "Product Backlog Item": "PBI",
    Bug: "BUG",
    Task: "TSK",
    Impediment: "IMP",
  };

  return (
    <div className="sprint-context">
      <button
        className="sprint-context-toggle"
        onClick={() => setExpanded((e) => !e)}
      >
        <svg
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          strokeWidth="2"
          style={{ width: 14, height: 14, flexShrink: 0 }}
        >
          <rect x="3" y="3" width="18" height="18" rx="2" />
          <path d="M9 12h6M12 9v6" />
        </svg>
        <span className="sprint-context-label">
          Your sprint: {data.items.length} item
          {data.items.length !== 1 ? "s" : ""}
        </span>
        <span className="sprint-context-name">{data.sprint}</span>
        <Icon.Chevron
          style={{
            width: 12,
            height: 12,
            marginLeft: "auto",
            transform: expanded ? "rotate(180deg)" : "rotate(0deg)",
            transition: "transform 150ms ease",
          }}
        />
      </button>
      {expanded && (
        <div className="sprint-context-items">
          {data.items.map((item) => (
            <div key={item.id} className="sprint-item">
              <span
                className={`sprint-item-type ${(TYPE_ICON[item.type] || "TSK").toLowerCase()}`}
              >
                {TYPE_ICON[item.type] || item.type?.slice(0, 3).toUpperCase()}
              </span>
              <span className="sprint-item-title">
                #{item.id} {item.title}
              </span>
              <span
                className={`sprint-item-state ${STATE_CSS[item.state] || ""}`}
              >
                {item.state}
              </span>
            </div>
          ))}
          <div className="sprint-context-hint">
            Mention these in your check-in — Pulse will offer to update their
            status.
          </div>
        </div>
      )}
    </div>
  );
}

// ── Sprint progress card (right rail) ───────────────────────────────────────
// Shows team sprint progress bar + open impediments count.

function SprintRailCard({ authToken }) {
  const [sprint, setSprint] = useState(null);
  const [loading, setLoading] = useState(true);
  const apiBase = window.PULSE_CONFIG?.apiBase || "http://localhost:8000";

  useEffect(() => {
    if (!authToken) return;
    fetch(`${apiBase}/ado/sprint`, {
      headers: { Authorization: `Bearer ${authToken}` },
    })
      .then((r) => {
        if (r.status === 404) return null;
        if (!r.ok) throw new Error("Failed");
        return r.json();
      })
      .then((d) => {
        setSprint(d);
        setLoading(false);
      })
      .catch(() => setLoading(false));
  }, [authToken]);

  if (loading || !sprint || !sprint.summary) return null;

  const { summary } = sprint;
  const pct =
    summary.total > 0 ? Math.round((summary.done / summary.total) * 100) : 0;

  const sprintEnd = sprint.sprint?.end ? new Date(sprint.sprint.end) : null;
  const daysLeft = sprintEnd
    ? Math.max(0, Math.ceil((sprintEnd - new Date()) / 86400000))
    : null;

  return (
    <div className="rr-card sprint-rail-card">
      <div className="rr-head">
        <svg
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          strokeWidth="2"
          style={{ width: 16, height: 16 }}
        >
          <rect x="3" y="3" width="18" height="18" rx="2" />
          <path d="M9 12h6M12 9v6" />
        </svg>
        <div className="rr-title">{sprint.sprint?.name || "Sprint"}</div>
        {daysLeft !== null && (
          <span
            style={{
              marginLeft: "auto",
              fontSize: 11,
              color: daysLeft <= 2 ? "var(--danger)" : "var(--ink-3)",
              fontWeight: 500,
            }}
          >
            {daysLeft}d left
          </span>
        )}
      </div>

      <div className="sprint-progress">
        <div className="sprint-progress-bar">
          <div className="sprint-progress-fill" style={{ width: `${pct}%` }} />
        </div>
        <div className="sprint-progress-stats">
          <span>
            <strong>{summary.done}</strong> done
          </span>
          <span>
            <strong>{summary.in_progress}</strong> in progress
          </span>
          <span>
            <strong>{summary.new}</strong> new
          </span>
        </div>
      </div>
    </div>
  );
}

// ── ADO Action Cards (confirm-before-write) ─────────────────────────────────
// Shown after a check-in when ADO suggests state changes / comments / tasks.

function ADOActionCards({ authToken, onDone }) {
  const [actions, setActions] = useState([]);
  const [loading, setLoading] = useState(true);
  const [processing, setProcessing] = useState(new Set());
  const apiBase = window.PULSE_CONFIG?.apiBase || "http://localhost:8000";

  useEffect(() => {
    if (!authToken) return;
    const poll = () => {
      fetch(`${apiBase}/ado/actions/pending`, {
        headers: { Authorization: `Bearer ${authToken}` },
      })
        .then((r) => (r.ok ? r.json() : { actions: [] }))
        .then((d) => {
          setActions(d.actions || []);
          setLoading(false);
        })
        .catch(() => setLoading(false));
    };
    poll();
    // Poll once more after 3s (actions are generated async after check-in)
    const t = setTimeout(poll, 3000);
    return () => clearTimeout(t);
  }, [authToken]);

  const handleConfirm = async (id) => {
    setProcessing((s) => new Set(s).add(id));
    await fetch(`${apiBase}/ado/actions/${id}/confirm`, {
      method: "POST",
      headers: { Authorization: `Bearer ${authToken}` },
    });
    setActions((a) => a.filter((x) => x.id !== id));
    setProcessing((s) => {
      const n = new Set(s);
      n.delete(id);
      return n;
    });
  };

  const handleDismiss = async (id) => {
    setProcessing((s) => new Set(s).add(id));
    await fetch(`${apiBase}/ado/actions/${id}/dismiss`, {
      method: "POST",
      headers: { Authorization: `Bearer ${authToken}` },
    });
    setActions((a) => a.filter((x) => x.id !== id));
    setProcessing((s) => {
      const n = new Set(s);
      n.delete(id);
      return n;
    });
  };

  if (loading || actions.length === 0) return null;

  const ACTION_LABELS = {
    state_change: "Move to",
    add_comment: "Add comment",
    create_task: "Create task",
  };

  const ACTION_ICONS = {
    state_change: "→",
    add_comment: "\u{1f4ac}",
    create_task: "+",
  };

  return (
    <div className="ado-action-cards">
      <div className="ado-action-header">
        <svg
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          strokeWidth="2"
          style={{ width: 14, height: 14 }}
        >
          <rect x="3" y="3" width="18" height="18" rx="2" />
          <path d="M9 12h6M12 9v6" />
        </svg>
        <span>Suggested ADO updates</span>
      </div>
      {actions.map((a) => (
        <div key={a.id} className="ado-action-card">
          <div className="ado-action-top">
            <span className={`ado-action-type ${a.action_type}`}>
              {ACTION_LABELS[a.action_type] || a.action_type}
              {a.action_type === "state_change" && a.payload?.new_state
                ? ` ${a.payload.new_state}`
                : ""}
            </span>
            <span className="ado-action-item">
              #{a.work_item_id} {a.work_item_title}
            </span>
          </div>
          {a.payload?.text && (
            <div className="ado-action-preview">"{a.payload.text}"</div>
          )}
          {a.payload?.title && (
            <div className="ado-action-preview">New: {a.payload.title}</div>
          )}
          <div className="ado-action-buttons">
            <button
              className="btn ado-confirm"
              disabled={processing.has(a.id)}
              onClick={() => handleConfirm(a.id)}
            >
              {processing.has(a.id) ? "..." : "Confirm"}
            </button>
            <button
              className="btn ado-dismiss"
              disabled={processing.has(a.id)}
              onClick={() => handleDismiss(a.id)}
            >
              Dismiss
            </button>
          </div>
        </div>
      ))}
    </div>
  );
}

// ── Drift Nudges (shown in check-in modal) ──────────────────────────────────
// Gentle hints about mismatches between check-ins and ADO state.

function DriftNudges({ authToken }) {
  const [nudges, setNudges] = useState([]);
  const [dismissed, setDismissed] = useState(new Set());
  const [loading, setLoading] = useState(true);
  const apiBase = window.PULSE_CONFIG?.apiBase || "http://localhost:8000";

  useEffect(() => {
    if (!authToken) return;
    fetch(`${apiBase}/ado/drift`, {
      headers: { Authorization: `Bearer ${authToken}` },
    })
      .then((r) => (r.ok ? r.json() : { nudges: [] }))
      .then((d) => {
        setNudges(d.nudges || []);
        setLoading(false);
      })
      .catch(() => setLoading(false));
  }, [authToken]);

  const visible = nudges.filter((_, i) => !dismissed.has(i));
  if (loading || visible.length === 0) return null;

  const NUDGE_ICONS = {
    said_done_still_open: "⚠️",
    stale_item: "⏳",
    untracked_work: "📝",
  };

  const NUDGE_LABELS = {
    said_done_still_open: "Still open in ADO",
    stale_item: "Stale",
    untracked_work: "Untracked",
  };

  return (
    <div className="drift-nudges">
      <div className="drift-nudges-header">
        <svg
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          strokeWidth="2"
          style={{ width: 13, height: 13 }}
        >
          <circle cx="12" cy="12" r="10" />
          <path d="M12 8v4M12 16h.01" />
        </svg>
        <span>ADO sync hints</span>
      </div>
      {nudges.map((nudge, i) =>
        dismissed.has(i) ? null : (
          <div key={i} className={`drift-nudge ${nudge.type}`}>
            <div className="drift-nudge-top">
              <span className="drift-nudge-label">
                {NUDGE_LABELS[nudge.type] || nudge.type}
              </span>
              {nudge.work_item_id && (
                <span className="drift-nudge-id">#{nudge.work_item_id}</span>
              )}
              <button
                className="drift-nudge-dismiss"
                onClick={() => setDismissed((s) => new Set(s).add(i))}
                aria-label="Dismiss"
              >
                &times;
              </button>
            </div>
            <div className="drift-nudge-message">{nudge.message}</div>
          </div>
        ),
      )}
    </div>
  );
}

window.SprintContext = SprintContext;
window.SprintRailCard = SprintRailCard;
window.ADOActionCards = ADOActionCards;
window.DriftNudges = DriftNudges;
