'use client';

import { useEffect, useState, useCallback } from 'react';
import Link from 'next/link';
import { PageHeader } from '@bytelyst/dashboard-components';
import { Button } from '@/components/ui/Primitives';
import { useAuth } from '@/lib/auth-context';
import {
  listJobs,
  submitJob,
  availableEnginesForProduct,
  FLEET_ENGINES,
  type FleetJob,
  type FleetEngine,
} from '@/lib/fleet-client';

const STAGES = [
  'queued',
  'blocked',
  'assigned',
  'building',
  'review',
  'testing',
  'shipped',
  'failed',
  'dead_letter',
] as const;

// Semantic badge styling per stage (token-backed Tailwind colors).
const STAGE_STYLE: Record<string, string> = {
  queued: 'bg-muted text-muted-foreground',
  blocked: 'bg-amber-500/15 text-amber-700 dark:text-amber-400',
  assigned: 'bg-sky-500/15 text-sky-700 dark:text-sky-400',
  building: 'bg-blue-500/15 text-blue-700 dark:text-blue-400',
  review: 'bg-amber-500/15 text-amber-700 dark:text-amber-400',
  testing: 'bg-purple-500/15 text-purple-700 dark:text-purple-400',
  shipped: 'bg-green-600/15 text-green-700 dark:text-green-400',
  failed: 'bg-destructive/15 text-destructive',
  dead_letter: 'bg-destructive/15 text-destructive',
};
const stageStyle = (s: string) => STAGE_STYLE[s] ?? 'bg-muted text-muted-foreground';
const stageLabel = (s: string) => s.replace(/_/g, ' ');
const PRIORITY_STYLE: Record<string, string> = {
  critical: 'text-destructive font-semibold',
  high: 'text-amber-700 dark:text-amber-400',
  medium: 'text-muted-foreground',
  low: 'text-muted-foreground',
};
const POLL_INTERVAL = 30_000;

// MVP: PR-mode target repos (local checkouts under the factory's repo base).
// Base branch is fixed to `main`. Empty selection = no PR (plain job).
const FLEET_REPOS = [
  'learning_ai_common_plat',
  'learning_ai_devops_tools',
  'learning_voice_ai_agent',
  'learning_multimodal_memory_agents',
  'learning_ai_clock',
  'learning_ai_jarvis_jr',
  'learning_ai_fastgap',
  'learning_ai_peakpulse',
  'learning_ai_flowmonk',
  'learning_ai_notes',
  'learning_ai_trails',
  'learning_ai_efforise',
  'learning_ai_local_memory_gpt',
  'learning_ai_2nd_brain',
  'learning_ai_auth_app',
  'learning_agent_monitoring_fx',
  'learning_notif_scanr',
  'learning_ai_local_llms',
  'learning_ai_mac_tooling',
  'learning_ai_productivity_web',
  'learning_ai_webui_copilot',
];
const FLEET_BASE_BRANCH = 'main';

// Live factories on this host (one agent-queue daemon per product — see
// _start_fleet.sh). Selecting one routes the job to that factory's product (the
// factory polling that product claims it). The id matches the factory's
// AQ_FACTORY_ID so the labels line up with what the fleet dashboard shows.
const FLEET_FACTORIES = [
  { id: 'mac-lysnrai', label: 'mac-lysnrai — LysnrAI', productId: 'lysnrai' },
  { id: 'mac-chronomind', label: 'mac-chronomind — ChronoMind', productId: 'chronomind' },
  { id: 'mac-mindlyst', label: 'mac-mindlyst — MindLyst', productId: 'mindlyst' },
  { id: 'mac-nomgap', label: 'mac-nomgap — NomGap', productId: 'nomgap' },
];

export default function FleetJobsPage() {
  const { token } = useAuth();
  const [jobs, setJobs] = useState<FleetJob[]>([]);
  const [stage, setStage] = useState('');
  const [hideShipped, setHideShipped] = useState(false);
  const [search, setSearch] = useState('');
  const [loading, setLoading] = useState(true);

  // New-job form state
  const [showForm, setShowForm] = useState(false);
  const [factoryId, setFactoryId] = useState(FLEET_FACTORIES[0].id);
  const [body, setBody] = useState('');
  const [priority, setPriority] = useState<'critical' | 'high' | 'medium' | 'low'>('high');
  const [engine, setEngine] = useState<FleetEngine>('devin');
  // Engines the selected factory's product actually advertises ([] ⇒ unknown,
  // offer all). Keeps users from picking an engine the host can't run.
  const [engineOptions, setEngineOptions] = useState<FleetEngine[]>([]);
  // Empty by default: no agent-queue factory advertises a `build` capability
  // (caps are os:* / engine:* / node:* / has:*), so a non-empty default here makes
  // the job unroutable. Leave blank ⇒ any capable factory for the product claims it.
  const [caps, setCaps] = useState('');
  const [repo, setRepo] = useState('');
  const [verifyCmd, setVerifyCmd] = useState('');
  const [autoMerge, setAutoMerge] = useState(false);
  const [submitting, setSubmitting] = useState(false);
  const [submitMsg, setSubmitMsg] = useState<{ ok: boolean; text: string } | null>(null);

  // Fetch the full recent window once; stage / hide-shipped / search are applied
  // client-side so the stage counts stay accurate and filtering is instant.
  const refresh = useCallback(async () => {
    try {
      const res = await listJobs({ limit: '100' } as never);
      setJobs(res.jobs);
    } catch {
      /* degrade */
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    if (!token) return;
    refresh();
    const id = setInterval(refresh, POLL_INTERVAL);
    return () => clearInterval(id);
  }, [token, refresh]);

  // Restore the hide-shipped preference (client-only; avoids hydration mismatch).
  useEffect(() => {
    setHideShipped(localStorage.getItem('fleet_hide_shipped') === '1');
  }, []);

  // When the target factory changes, learn which engines its product advertises
  // and constrain the picker (so you can't pick an engine the host can't run).
  useEffect(() => {
    if (!token || !showForm) return;
    const factory = FLEET_FACTORIES.find(f => f.id === factoryId) ?? FLEET_FACTORIES[0];
    let cancelled = false;
    availableEnginesForProduct(factory.productId)
      .then(engines => {
        if (cancelled) return;
        setEngineOptions(engines);
        // Keep the selection valid: prefer the current pick, else devin, else first.
        if (engines.length > 0) {
          setEngine(prev =>
            engines.includes(prev) ? prev : engines.includes('devin') ? 'devin' : engines[0]!
          );
        }
      })
      .catch(() => {
        if (!cancelled) setEngineOptions([]);
      });
    return () => {
      cancelled = true;
    };
  }, [token, showForm, factoryId]);
  const toggleHideShipped = useCallback((next: boolean) => {
    setHideShipped(next);
    localStorage.setItem('fleet_hide_shipped', next ? '1' : '0');
  }, []);

  // Stage counts (over everything fetched) + the filtered, sorted view.
  const stageCounts = jobs.reduce<Record<string, number>>((acc, j) => {
    acc[j.stage] = (acc[j.stage] ?? 0) + 1;
    return acc;
  }, {});
  const q = search.trim().toLowerCase();
  const visible = jobs
    .filter(j => {
      if (stage && j.stage !== stage) return false;
      if (hideShipped && j.stage === 'shipped') return false;
      if (q) {
        const hay = `${j.idempotencyKey} ${j.repo ?? ''} ${j.id}`.toLowerCase();
        if (!hay.includes(q)) return false;
      }
      return true;
    })
    .sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt));

  const handleSubmit = useCallback(
    async (asDraft = false) => {
      if (!body.trim()) {
        setSubmitMsg({ ok: false, text: 'Job body is required.' });
        return;
      }
      setSubmitting(true);
      setSubmitMsg(null);
      try {
        const capabilities = caps
          .split(',')
          .map(c => c.trim())
          .filter(Boolean);
        const factory = FLEET_FACTORIES.find(f => f.id === factoryId) ?? FLEET_FACTORIES[0];
        const { job } = await submitJob(
          {
            idempotencyKey: `ui-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
            bodyMd: body.trim(),
            priority,
            capabilities,
            engine,
            ...(asDraft ? { draft: true } : {}),
            ...(repo
              ? {
                  repo,
                  baseBranch: FLEET_BASE_BRANCH,
                  ...(verifyCmd.trim() ? { verify: verifyCmd.trim() } : {}),
                  ...(autoMerge ? { autoMerge: true } : {}),
                }
              : {}),
          },
          factory.productId
        );
        // Route the dashboard view to the factory's product so the job is visible.
        if (typeof window !== 'undefined') {
          localStorage.setItem('tracker_selected_product', factory.productId);
        }
        setSubmitMsg({
          ok: true,
          text:
            `${asDraft ? 'Saved draft' : 'Submitted'} ${job.id} to ${factory.id} (${factory.productId}, stage: ${job.stage})` +
            (repo
              ? ` — PR mode: ${repo}@${FLEET_BASE_BRANCH}${verifyCmd.trim() ? ' +verify' : ''}${autoMerge ? ' +auto-merge' : ''}`
              : ' — no PR (plain job)') +
            (asDraft ? ' — open it to edit + submit.' : '.'),
        });
        setBody('');
        await refresh();
      } catch (err: unknown) {
        const msg = err instanceof Error ? err.message : 'Submit failed.';
        setSubmitMsg({ ok: false, text: msg });
      } finally {
        setSubmitting(false);
      }
    },
    [body, caps, priority, engine, repo, verifyCmd, autoMerge, factoryId, refresh]
  );

  return (
    <div className="p-6 space-y-6">
      <PageHeader title="Fleet Jobs" />

      {/* New job */}
      <div className="rounded-lg border">
        <button
          type="button"
          onClick={() => setShowForm(v => !v)}
          className="flex w-full items-center justify-between px-4 py-3 text-sm font-medium"
          aria-expanded={showForm}
        >
          <span>New Job</span>
          <span className="text-muted-foreground">{showForm ? '−' : '+'}</span>
        </button>
        {showForm && (
          <div className="space-y-3 border-t px-4 py-4">
            <div>
              <label htmlFor="job-factory" className="mb-1 block text-sm font-medium">
                Factory
              </label>
              <select
                id="job-factory"
                value={factoryId}
                onChange={e => setFactoryId(e.target.value)}
                className="rounded border bg-background px-2 py-1 text-sm"
              >
                {FLEET_FACTORIES.map(f => (
                  <option key={f.id} value={f.id}>
                    {f.label}
                  </option>
                ))}
              </select>
            </div>
            <div>
              <label htmlFor="job-body" className="mb-1 block text-sm font-medium">
                Task (markdown)
              </label>
              <textarea
                id="job-body"
                value={body}
                onChange={e => setBody(e.target.value)}
                rows={4}
                placeholder="e.g. Create a file HELLO.md with one line: hello. Then stop."
                className="w-full rounded border bg-background px-2 py-1 text-sm font-mono"
              />
            </div>
            <div className="flex flex-wrap items-end gap-4">
              <div>
                <label htmlFor="job-priority" className="mb-1 block text-sm font-medium">
                  Priority
                </label>
                <select
                  id="job-priority"
                  value={priority}
                  onChange={e =>
                    setPriority(e.target.value as 'critical' | 'high' | 'medium' | 'low')
                  }
                  className="rounded border bg-background px-2 py-1 text-sm"
                >
                  <option value="critical">critical</option>
                  <option value="high">high</option>
                  <option value="medium">medium</option>
                  <option value="low">low</option>
                </select>
              </div>
              <div>
                <label htmlFor="job-engine" className="mb-1 block text-sm font-medium">
                  Engine
                </label>
                <select
                  id="job-engine"
                  value={engine}
                  onChange={e => setEngine(e.target.value as FleetEngine)}
                  className="rounded border bg-background px-2 py-1 text-sm"
                >
                  {(engineOptions.length > 0 ? engineOptions : FLEET_ENGINES).map(e => (
                    <option key={e} value={e}>
                      {e}
                    </option>
                  ))}
                </select>
                {engineOptions.length > 0 && (
                  <p className="mt-1 text-xs text-muted-foreground">advertised by this factory</p>
                )}
              </div>
              <div>
                <label htmlFor="job-caps" className="mb-1 block text-sm font-medium">
                  Capabilities (comma-separated)
                </label>
                <input
                  id="job-caps"
                  value={caps}
                  onChange={e => setCaps(e.target.value)}
                  placeholder="optional — e.g. engine:devin, has:docker"
                  className="rounded border bg-background px-2 py-1 text-sm"
                />
              </div>
              <div>
                <label htmlFor="job-repo" className="mb-1 block text-sm font-medium">
                  Repo (optional — opens a PR)
                </label>
                <select
                  id="job-repo"
                  value={repo}
                  onChange={e => setRepo(e.target.value)}
                  className="rounded border bg-background px-2 py-1 text-sm font-mono"
                >
                  <option value="">— none (no PR) —</option>
                  {FLEET_REPOS.map(r => (
                    <option key={r} value={r}>
                      {r}
                    </option>
                  ))}
                </select>
                {repo && (
                  <p className="mt-1 text-xs text-muted-foreground">
                    PR against <span className="font-mono">{FLEET_BASE_BRANCH}</span>
                  </p>
                )}
              </div>
              {repo && (
                <div>
                  <label htmlFor="job-verify" className="mb-1 block text-sm font-medium">
                    Verify command (optional)
                  </label>
                  <input
                    id="job-verify"
                    value={verifyCmd}
                    onChange={e => setVerifyCmd(e.target.value)}
                    placeholder="e.g. pnpm install && pnpm test"
                    className="w-64 rounded border bg-background px-2 py-1 text-sm font-mono"
                  />
                  <p className="mt-1 text-xs text-muted-foreground">
                    Runs in the checkout; the PR opens only if it passes.
                  </p>
                </div>
              )}
              {repo && (
                <label className="flex items-center gap-2 self-end pb-1 text-sm">
                  <input
                    type="checkbox"
                    checked={autoMerge}
                    onChange={e => setAutoMerge(e.target.checked)}
                    aria-label="Auto-merge the PR when opened"
                  />
                  Auto-merge PR
                </label>
              )}
              <Button
                variant="secondary"
                onClick={() => handleSubmit(true)}
                disabled={submitting}
                aria-label="Save as draft (not submitted)"
              >
                {submitting ? 'Saving…' : 'Save as draft'}
              </Button>
              <Button
                onClick={() => handleSubmit(false)}
                disabled={submitting}
                aria-label="Submit new job"
              >
                {submitting ? 'Submitting…' : 'Submit'}
              </Button>
            </div>
            {submitMsg && (
              <p
                className={`text-sm ${submitMsg.ok ? 'text-green-600 dark:text-green-400' : 'text-destructive'}`}
                role="status"
              >
                {submitMsg.text}
              </p>
            )}
          </div>
        )}
      </div>

      {/* Filters */}
      <div className="space-y-3">
        {/* Stage chips with live counts (click to filter) */}
        <div className="flex flex-wrap items-center gap-1.5">
          <button
            type="button"
            onClick={() => setStage('')}
            className={`rounded-full border px-2.5 py-1 text-xs font-medium ${
              stage === '' ? 'bg-primary text-primary-foreground border-primary' : 'hover:bg-muted'
            }`}
          >
            All <span className="opacity-70">{jobs.length}</span>
          </button>
          {STAGES.filter(s => stageCounts[s]).map(s => (
            <button
              key={s}
              type="button"
              onClick={() => setStage(stage === s ? '' : s)}
              className={`rounded-full px-2.5 py-1 text-xs font-medium ${stageStyle(s)} ${
                stage === s ? 'ring-2 ring-primary ring-offset-1 ring-offset-background' : ''
              }`}
            >
              {stageLabel(s)} <span className="opacity-70">{stageCounts[s]}</span>
            </button>
          ))}
        </div>

        {/* Search + hide-shipped */}
        <div className="flex flex-wrap items-center gap-4">
          <input
            type="search"
            value={search}
            onChange={e => setSearch(e.target.value)}
            placeholder="Search key / repo / id…"
            className="w-64 rounded border bg-background px-2 py-1 text-sm"
            aria-label="Search jobs"
          />
          <label className="flex items-center gap-2 text-sm">
            <input
              type="checkbox"
              checked={hideShipped}
              onChange={e => toggleHideShipped(e.target.checked)}
              aria-label="Hide shipped jobs"
            />
            Hide shipped
          </label>
          <span className="text-xs text-muted-foreground">
            {visible.length} of {jobs.length} shown
          </span>
        </div>
      </div>

      {/* Table */}
      {loading ? (
        <p className="text-muted-foreground">Loading jobs...</p>
      ) : visible.length === 0 ? (
        <p className="text-muted-foreground">
          {jobs.length === 0 ? 'No jobs yet — submit one above.' : 'No jobs match the filters.'}
        </p>
      ) : (
        <div className="overflow-x-auto rounded-lg border">
          <table className="w-full text-sm" aria-label="Fleet jobs table">
            <thead>
              <tr className="border-b bg-muted/40 text-left text-xs uppercase tracking-wide text-muted-foreground">
                <th className="px-3 py-2">Job</th>
                <th className="px-3 py-2">Stage</th>
                <th className="px-3 py-2">Priority</th>
                <th className="px-3 py-2">Repo</th>
                <th className="px-3 py-2 text-right">Attempts</th>
                <th className="px-3 py-2 text-right">Created</th>
              </tr>
            </thead>
            <tbody>
              {visible.map(j => (
                <tr key={j.id} className="border-b last:border-0 hover:bg-muted/40">
                  <td className="px-3 py-2">
                    <Link
                      href={`/dashboard/fleet/jobs/${j.id}`}
                      className="font-mono text-xs hover:underline"
                      aria-label={`View job ${j.idempotencyKey}`}
                    >
                      {j.idempotencyKey}
                    </Link>
                    {j.kind !== 'leaf' && (
                      <span className="ml-2 text-[10px] text-muted-foreground">{j.kind}</span>
                    )}
                  </td>
                  <td className="px-3 py-2">
                    <span
                      className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${stageStyle(j.stage)}`}
                    >
                      {stageLabel(j.stage)}
                    </span>
                  </td>
                  <td className={`px-3 py-2 capitalize ${PRIORITY_STYLE[j.priority] ?? ''}`}>
                    {j.priority}
                  </td>
                  <td className="px-3 py-2 font-mono text-xs">
                    {j.repo ? (
                      <span title={`${j.repo}@${j.baseBranch ?? 'main'}`}>{j.repo}</span>
                    ) : (
                      <span className="text-muted-foreground">—</span>
                    )}
                  </td>
                  <td className="px-3 py-2 text-right tabular-nums">{j.attempts}</td>
                  <td className="px-3 py-2 text-right text-xs text-muted-foreground whitespace-nowrap">
                    {new Date(j.createdAt).toLocaleString()}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}
