"use client";

/**
 * TimeTrackingSmartsheetCard — admin `/admin/water-log/settings`
 * card for the Time Tracking → Smartsheet integration (Cycle 5).
 *
 * Cycle 7: this card no longer owns the API token. The token lives
 * on the workspace (one per brand, owned by the hub card above).
 * This card only manages the per-feature mapping: sheet ID + column
 * mapping + frequency + sync enabled + recent activity.
 *
 * Self-contained client component. Takes `brandId` as a prop per
 * the brand-isolation convention.
 */

import { useCallback, useEffect, useReducer, useState } from "react";
import {
  getTTSmartsheetConfig,
  saveTTSmartsheetConfig,
  testTTSmartsheetConnection,
  getTTSmartsheetRecent,
  disableTTSmartsheet,
  getTTSmartsheetQueueSummary,
  type TTSmartsheetConfigResponse,
  type TTSmartsheetRecentEntry,
  type TTSmartsheetQueueSummary,
} from "@/actions/time-tracking/smartsheet";
import { TT_SMARTSHEET_FREQUENCIES } from "@/db/schema/time-tracking";
import type {
  TTSmartsheetColumnMapping,
  TTSmartsheetColumnKey,
  TTSmartsheetFrequency,
} from "@/db/schema/time-tracking";
import { formatDateTime } from "@/lib/format-date";

type Props = {
  brandId: string;
};

type Status =
  | { kind: "idle" }
  | { kind: "saved-at"; iso: string }
  | { kind: "error"; message: string };

type State = {
  config: TTSmartsheetConfigResponse | null;
  sheetIdInput: string;
  frequency: TTSmartsheetFrequency;
  syncEnabled: boolean;
  columns: TTColumnOption[];
  columnMapping: TTSmartsheetColumnMapping;
  recent: TTSmartsheetRecentEntry[];
  queue: TTSmartsheetQueueSummary;
  loading: boolean;
  testing: boolean;
  saving: boolean;
  status: Status;
};

type TTColumnOption = {
  id: string;
  title: string;
  type: string;
};

type Action =
  | { type: "SET_CONFIG"; config: TTSmartsheetConfigResponse }
  | { type: "SET_SHEET_ID"; value: string }
  | { type: "SET_FREQUENCY"; value: TTSmartsheetFrequency }
  | { type: "SET_SYNC_ENABLED"; value: boolean }
  | { type: "SET_COLUMNS"; columns: NonNullable<State["columns"]> }
  | { type: "SET_COL_MAPPING_VALUE"; key: TTSmartsheetColumnKey; columnId: string | null }
  | { type: "SET_RECENT"; entries: TTSmartsheetRecentEntry[] }
  | { type: "SET_QUEUE"; queue: TTSmartsheetQueueSummary }
  | { type: "SET_LOADING"; loading: boolean }
  | { type: "SET_TESTING"; value: boolean }
  | { type: "SET_SAVING"; value: boolean }
  | { type: "SET_STATUS"; value: Status };

const EMPTY_MAPPING: TTSmartsheetColumnMapping = {
  log_id: "",
  clock_in: "",
  clock_out: null,
  worker: null,
  task: null,
  hours: null,
  lunch_minutes: null,
  notes: null,
};

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case "SET_CONFIG": {
      const cfg = action.config;
      return {
        ...state,
        config: cfg,
        sheetIdInput: cfg.sheetId ?? "",
        frequency: cfg.syncFrequency,
        syncEnabled: cfg.syncEnabled,
        columnMapping: cfg.columnMapping ?? { ...EMPTY_MAPPING },
        loading: false,
      };
    }
    case "SET_SHEET_ID":
      return { ...state, sheetIdInput: action.value };
    case "SET_FREQUENCY":
      return { ...state, frequency: action.value };
    case "SET_SYNC_ENABLED":
      return { ...state, syncEnabled: action.value };
    case "SET_COLUMNS":
      return { ...state, columns: action.columns };
    case "SET_COL_MAPPING_VALUE":
      return {
        ...state,
        columnMapping: {
          ...state.columnMapping,
          [action.key]: action.columnId,
        },
      };
    case "SET_RECENT":
      return { ...state, recent: action.entries };
    case "SET_QUEUE":
      return { ...state, queue: action.queue };
    case "SET_LOADING":
      return { ...state, loading: action.loading };
    case "SET_TESTING":
      return { ...state, testing: action.value };
    case "SET_SAVING":
      return { ...state, saving: action.value };
    case "SET_STATUS":
      return { ...state, status: action.value };
  }
}

function initialState(): State {
  return {
    config: null,
    sheetIdInput: "",
    frequency: "hourly",
    syncEnabled: false,
    columns: [],
    columnMapping: { ...EMPTY_MAPPING },
    recent: [],
    queue: { pending: 0, syncing: 0, synced: 0, failed: 0 },
    loading: true,
    testing: false,
    saving: false,
    status: { kind: "idle" },
  };
}

export function TimeTrackingSmartsheetCard({ brandId }: Props) {
  const [state, dispatch] = useReducer(reducer, undefined, initialState);
  const [, force] = useState({}); // for non-react subscribed re-renders

  const refresh = useCallback(async () => {
    const [cfg, recent, queue] = await Promise.all([
      getTTSmartsheetConfig(brandId),
      getTTSmartsheetRecent(brandId, 10),
      getTTSmartsheetQueueSummary(brandId),
    ]);
    dispatch({ type: "SET_CONFIG", config: cfg });
    dispatch({ type: "SET_RECENT", entries: recent });
    dispatch({ type: "SET_QUEUE", queue });
  }, [brandId]);

  useEffect(() => {
    void refresh();
  }, [refresh]);

  // Cycle 7: Test Connection uses the workspace's saved token (no
  // per-feature token to pass). The workspace action
  // `testSmartsheetWorkspaceConnection` is the hub's button; here we
  // call the per-feature test action with no token, which falls
  // through to the workspace resolver.
  const onTestConnection = useCallback(async () => {
    dispatch({ type: "SET_TESTING", value: true });
    dispatch({ type: "SET_STATUS", value: { kind: "idle" } });
    const result = await testTTSmartsheetConnection(brandId, {
      sheetId: state.sheetIdInput,
      // No `token` — the action pulls the saved workspace token.
    });
    if (!result.success) {
      dispatch({
        type: "SET_STATUS",
        value: { kind: "error", message: result.error },
      });
      dispatch({ type: "SET_TESTING", value: false });
      return;
    }
    dispatch({ type: "SET_COLUMNS", columns: result.columns });
    dispatch({ type: "SET_STATUS", value: { kind: "idle" } });
    dispatch({ type: "SET_TESTING", value: false });
    force({});
  }, [brandId, state.sheetIdInput]);

  const onSave = useCallback(async () => {
    dispatch({ type: "SET_SAVING", value: true });
    dispatch({ type: "SET_STATUS", value: { kind: "idle" } });
    const result = await saveTTSmartsheetConfig(brandId, {
      sheetId: state.sheetIdInput,
      // Cycle 7: token is owned by the workspace; this field is
      // ignored on save but kept for type compat.
      token: "",
      syncEnabled: state.syncEnabled,
      syncFrequency: state.frequency,
      columnMapping: state.columnMapping,
    });
    if (!result.success) {
      dispatch({
        type: "SET_STATUS",
        value: { kind: "error", message: result.error },
      });
      dispatch({ type: "SET_SAVING", value: false });
      return;
    }
    dispatch({
      type: "SET_CONFIG",
      config: result.config,
    });
    dispatch({
      type: "SET_STATUS",
      value: { kind: "saved-at", iso: new Date().toISOString() },
    });
    dispatch({ type: "SET_SAVING", value: false });
  }, [brandId, state]);

  const onDisable = useCallback(async () => {
    dispatch({ type: "SET_SAVING", value: true });
    await disableTTSmartsheet(brandId);
    await refresh();
    dispatch({ type: "SET_SAVING", value: false });
    dispatch({
      type: "SET_STATUS",
      value: { kind: "saved-at", iso: new Date().toISOString() },
    });
  }, [brandId, refresh]);

  if (state.loading) {
    return (
      <div className="rounded-2xl border border-[#e6dfd1] bg-white p-6">
        <div className="h-5 w-40 bg-[#fdfaf2] animate-pulse rounded" />
        <div className="mt-3 h-4 w-72 bg-[#fdfaf2] animate-pulse rounded" />
      </div>
    );
  }

  const hasWorkspaceToken = state.config?.hasToken === true;
  const maskedToken = state.config?.maskedToken ?? null;

  return (
    <div
      className="rounded-2xl border border-[#e6dfd1] bg-white p-6 shadow-sm"
      data-test="tt-smartsheet-card"
    >
      <div className="mb-4 flex items-start justify-between">
        <div>
          <h2 className="text-xl font-bold text-[#1a4d2e]">
            Time Tracking → Smartsheet
          </h2>
          <p className="mt-1 text-sm text-[rgba(60,60,67,0.65)]">
            Push every closed clock-out to a sheet inside the connected
            Smartsheet workbook. The API token is managed by the hub
            card above; this card only configures the sheet mapping.
          </p>
        </div>
        <label className="flex cursor-pointer items-center gap-2 text-sm font-medium text-[#1a4d2e]">
          <input
            type="checkbox"
            className="h-4 w-4 rounded border-[#1a4d2e] accent-[#1a4d2e]"
            checked={state.syncEnabled}
            onChange={(e) =>
              dispatch({
                type: "SET_SYNC_ENABLED",
                value: e.target.checked,
              })
            }
            data-test="tt-smartsheet-enabled"
          />
          Enabled
        </label>
      </div>

      {/* Workspace token reference */}
      <div className="mb-4 rounded-md border border-[#e6dfd1] bg-[#fdfaf2] px-3 py-2 text-xs text-[rgba(60,60,67,0.65)]">
        {hasWorkspaceToken && maskedToken ? (
          <>
            Using workbook token{" "}
            <span className="font-mono text-[#1a4d2e]">{maskedToken}</span>{" "}
            from the hub card above.
          </>
        ) : (
          <>
            ⚠ No Smartsheet workbook is connected yet. Save the hub card
            above with an API token before configuring this sheet.
          </>
        )}
      </div>

      <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
        <div className="sm:col-span-2">
          <label className="mb-1 block text-xs font-semibold uppercase tracking-wide text-[rgba(60,60,67,0.65)]">
            Sheet ID or URL
          </label>
          <input
            type="text"
            placeholder="e.g. 8309876543210123"
            value={state.sheetIdInput}
            onChange={(e) =>
              dispatch({ type: "SET_SHEET_ID", value: e.target.value })
            }
            className="w-full rounded-md border border-[#e6dfd1] bg-[#fdfaf2] px-3 py-2 text-sm"
            data-test="tt-smartsheet-sheet-id"
          />
          <p className="mt-1 text-xs text-[rgba(60,60,67,0.55)]">
            Pick the sheet inside the workbook where clock-outs should land.
          </p>
        </div>
        <div>
          <label className="mb-1 block text-xs font-semibold uppercase tracking-wide text-[rgba(60,60,67,0.65)]">
            Frequency
          </label>
          <select
            value={state.frequency}
            onChange={(e) =>
              dispatch({
                type: "SET_FREQUENCY",
                value: e.target.value as TTSmartsheetFrequency,
              })
            }
            className="w-full rounded-md border border-[#e6dfd1] bg-[#fdfaf2] px-3 py-2 text-sm"
            data-test="tt-smartsheet-frequency"
          >
            {TT_SMARTSHEET_FREQUENCIES.map((f) => (
              <option key={f} value={f}>
                {f.replace(/_/g, " ")}
              </option>
            ))}
          </select>
        </div>
      </div>

      <div className="mt-4 flex flex-wrap items-center gap-2">
        <button
          type="button"
          disabled={state.testing || !state.sheetIdInput}
          onClick={onTestConnection}
          className="rounded-md border border-[#1a4d2e] bg-white px-3 py-1.5 text-sm font-semibold text-[#1a4d2e] hover:bg-[#fdfaf2] disabled:cursor-not-allowed disabled:opacity-50"
          data-test="tt-smartsheet-test"
        >
          {state.testing ? "Testing…" : "Test Connection"}
        </button>
        <button
          type="button"
          disabled={state.saving}
          onClick={onSave}
          className="rounded-md bg-[#1a4d2e] px-3 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-[#14432a] disabled:cursor-not-allowed disabled:opacity-50"
          data-test="tt-smartsheet-save"
        >
          {state.saving ? "Saving…" : "Save"}
        </button>
        {state.config?.configured && state.syncEnabled && (
          <button
            type="button"
            disabled={state.saving}
            onClick={onDisable}
            className="rounded-md border border-[#a4452b] bg-white px-3 py-1.5 text-sm font-semibold text-[#a4452b] hover:bg-[#fdfaf2] disabled:cursor-not-allowed disabled:opacity-50"
          >
            Disable
          </button>
        )}
        <span className="ml-2 text-xs text-[rgba(60,60,67,0.55)]">
          {state.status.kind === "saved-at"
            ? `Saved at ${formatDateTime(new Date(state.status.iso))}`
            : state.status.kind === "error"
              ? state.status.message
              : state.config?.lastSyncAt
                ? `Last sync ${formatDateTime(new Date(state.config.lastSyncAt))}`
                : "Never synced"}
        </span>
      </div>

      {state.columns.length > 0 && (
        <ColumnMappingPanel
          columns={state.columns}
          mapping={state.columnMapping}
          onChange={(key, columnId) =>
            dispatch({
              type: "SET_COL_MAPPING_VALUE",
              key,
              columnId,
            })
          }
        />
      )}

      <RecentActivity recent={state.recent} queue={state.queue} />
    </div>
  );
}

function ColumnMappingPanel({
  columns,
  mapping,
  onChange,
}: {
  columns: NonNullable<State["columns"]>;
  mapping: TTSmartsheetColumnMapping;
  onChange: (key: TTSmartsheetColumnKey, columnId: string | null) => void;
}) {
  return (
    <div className="mt-6 rounded-xl border border-[#e6dfd1] bg-[#fdfaf2] p-4">
      <h3 className="text-sm font-semibold text-[#1a4d2e]">Column mapping</h3>
      <p className="mt-1 text-xs text-[rgba(60,60,67,0.65)]">
        Required: <span className="font-mono">log_id</span>,{" "}
        <span className="font-mono">clock_in</span>. Others optional.
      </p>
      <div className="mt-3 grid grid-cols-1 gap-2 sm:grid-cols-2">
        {(
          [
            ["log_id", "Log ID (UUID, for dedup)", true],
            ["clock_in", "Clock-in (timestamp)", true],
            ["clock_out", "Clock-out (timestamp)", false],
            ["worker", "Worker name", false],
            ["task", "Task name", false],
            ["hours", "Hours (decimal)", false],
            ["lunch_minutes", "Lunch minutes", false],
            ["notes", "Notes", false],
          ] as Array<[TTSmartsheetColumnKey, string, boolean]>
        ).map(([key, label, required]) => (
          <label key={key} className="block">
            <span className="block text-xs font-medium text-[rgba(60,60,67,0.65)]">
              {label}
              {required && (
                <span className="ml-1 text-[#a4452b]">*</span>
              )}
            </span>
            <select
              value={mapping[key] ?? ""}
              onChange={(e) =>
                onChange(
                  key,
                  e.target.value === "" ? null : e.target.value,
                )
              }
              className="mt-1 w-full rounded-md border border-[#e6dfd1] bg-white px-2 py-1.5 text-sm"
            >
              <option value="">— not mapped —</option>
              {columns.map((c) => (
                <option key={c.id} value={c.id}>
                  {c.title || `Column ${c.id}`}
                </option>
              ))}
            </select>
          </label>
        ))}
      </div>
    </div>
  );
}

function RecentActivity({
  recent,
  queue,
}: {
  recent: TTSmartsheetRecentEntry[];
  queue: TTSmartsheetQueueSummary;
}) {
  return (
    <div className="mt-6">
      <h3 className="text-sm font-semibold text-[#1a4d2e]">
        Recent activity
      </h3>
      <div className="mt-2 flex gap-3 text-xs text-[rgba(60,60,67,0.65)]">
        <span>Pending: {queue.pending}</span>
        <span>Syncing: {queue.syncing}</span>
        <span>Synced: {queue.synced}</span>
        <span>Failed: {queue.failed}</span>
      </div>
      <div className="mt-3 overflow-x-auto rounded-xl border border-[#e6dfd1]">
        <table className="w-full text-left text-sm">
          <thead className="bg-[#fdfaf2] text-xs uppercase tracking-wide text-[rgba(60,60,67,0.55)]">
            <tr>
              <th className="px-3 py-2">When</th>
              <th className="px-3 py-2">Action</th>
              <th className="px-3 py-2">Result</th>
              <th className="px-3 py-2">Error</th>
            </tr>
          </thead>
          <tbody>
            {recent.length === 0 && (
              <tr>
                <td
                  className="px-3 py-3 text-center text-[rgba(60,60,67,0.55)]"
                  colSpan={4}
                >
                  No sync attempts yet.
                </td>
              </tr>
            )}
            {recent.map((r) => (
              <tr key={r.id} className="border-t border-[#f0e9d8]">
                <td className="px-3 py-2 text-xs">
                  {formatDateTime(new Date(r.createdAt))}
                </td>
                <td className="px-3 py-2 text-xs">{r.action}</td>
                <td className="px-3 py-2 text-xs">
                  <span
                    className={
                      r.success
                        ? "inline-block rounded-full bg-[#1a4d2e]/10 px-2 py-0.5 text-[#1a4d2e]"
                        : "inline-block rounded-full bg-[#a4452b]/10 px-2 py-0.5 text-[#a4452b]"
                    }
                  >
                    {r.success ? "OK" : "FAIL"}
                  </span>
                </td>
                <td className="px-3 py-2 text-xs">
                  {r.error ?? "—"}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

export default TimeTrackingSmartsheetCard;