import type { ReactElement } from "react";
import { useState } from "react";

import type { LiveBuildRecord, LiveProbePayload, LiveSurface, Tone } from "../../types/domain";
import { asRecord, firstNonEmptyString, formatBeijingTime, formatDuration, shortToken, toneClass } from "../../utils";
import { StateTag } from "../shared/StateTag";
import { WorkbenchDialog } from "../shared/WorkbenchDialog";

interface WorkbenchBuildSummaryProps {
  live: LiveSurface | null;
}

interface ServiceRow {
  key: string;
  label: string;
  serviceId: string | null;
  commitShort: string | null;
  actualCommit: string | null;
  actualCommitShort: string | null;
  envCommitShort: string | null;
  revisionShort: string | null;
  tag: string | null;
  envImageTag: string | null;
  imageDigestShort: string | null;
  builtAt: string | null;
  status: Tone;
  reason: string | null;
  source: string | null;
  rollout: string | null;
}

export function WorkbenchBuildSummary({ live }: WorkbenchBuildSummaryProps): ReactElement {
  const [open, setOpen] = useState(false);
  const rows = buildRows(live);
  const latest = latestRow(live, rows);
  const overall = rows.some((row) => row.status === "ok") ? "ok" : rows.some((row) => row.status === "blocked") ? "blocked" : "pending";
  const latestText = latestSummaryText(latest);
  const countsText = countsSummary(live?.liveBuilds.data?.counts);

  return (
    <section className={`live-build-summary live-build-summary-compact live-build-summary-${overall} tone-border-${toneClass(overall)}`} data-live-build-summary>
      <details id="live-build-summary" className="live-build-details" open={false}>
        <summary id="live-build-latest" className="live-build-summary-line" onClick={(event) => event.preventDefault()}>
          <button
            id="live-build-toggle"
            className="status-chip-button live-build-summary-button"
            type="button"
            aria-haspopup="dialog"
            onClick={(event) => {
              event.preventDefault();
              event.stopPropagation();
              setOpen(true);
            }}
          >
            <span className="status-chip-label">最新镜像构建时间</span>
            <StateTag tone={toneClass(overall)} data-live-build-tone>{latest.builtAt ? formatBeijingTime(latest.builtAt, { withSeconds: true }) : "构建时间不可用"}</StateTag>
            <span className="status-chip-meta">{latestText}</span>
          </button>
        </summary>
        <ul id="live-build-list" className="live-build-list" role="list" hidden>
          {rows.map((row) => <BuildRowItem key={row.key} row={row} />)}
        </ul>
      </details>
      {open ? (
        <WorkbenchDialog id="live-build-dialog" title="构建版本明细" onClose={() => setOpen(false)}>
          <div className="live-build-dialog-summary">
            <p>{latestText}</p>
            {countsText ? <p>{countsText}</p> : null}
          </div>
          <ul className="live-build-list live-build-list-dialog" role="list">
            {rows.map((row) => <BuildRowItem key={row.key} row={row} />)}
          </ul>
        </WorkbenchDialog>
      ) : null}
    </section>
  );
}

function buildRows(live: LiveSurface | null): ServiceRow[] {
  const services = live?.liveBuilds.data?.services;
  if (services?.length) return services.map(rowFromLiveBuildRecord);
  const data = live?.healthLive.data;
  return [buildRowFromLive(data?.service, data?.commit, data?.image, data?.build, data?.revision, "health-live")];
}

function latestRow(live: LiveSurface | null, rows: ServiceRow[]): ServiceRow {
  const latest = live?.liveBuilds.data?.latest;
  if (latest) return rowFromLiveBuildRecord(latest);
  return rows.find((row) => row.builtAt) ?? rows[0] ?? emptyRow();
}

function rowFromLiveBuildRecord(record: LiveBuildRecord): ServiceRow {
  const build = asRecord(record.build);
  const image = asRecord(record.image);
  const commit = asRecord(record.commit);
  const desiredState = asRecord(record.desiredState);
  const liveMetadataMatch = asRecord(build?.liveMetadataMatch);
  const metadata = asRecord(liveMetadataMatch?.metadata);
  const serviceId = firstNonEmptyString(record.serviceId, record.name);
  const label = serviceId ?? "unknown-service";
  const actualCommit = firstNonEmptyString(commit?.id, record.revision);
  const envCommit = firstNonEmptyString(metadata?.commitId, metadata?.revision);
  const builtAt = firstNonEmptyString(build?.createdAt);
  const tag = firstNonEmptyString(image?.tag);
  const reason = firstNonEmptyString(build?.unavailableReason, record.reason);
  const source = sourceLabel(firstNonEmptyString(build?.metadataSource), record.healthUrl);
  return {
    key: serviceId ?? `${record.kind ?? "service"}-${tag ?? label}`,
    label,
    serviceId,
    commitShort: shortNullable(actualCommit, 12),
    actualCommit,
    actualCommitShort: shortNullable(actualCommit, 12),
    envCommitShort: shortNullable(envCommit, 12),
    revisionShort: shortNullable(record.revision, 12),
    tag,
    envImageTag: envImageLabel(tag, build?.source),
    imageDigestShort: shortNullable(image?.digest, 18),
    builtAt,
    status: builtAt ? "ok" : reason ? "warn" : toneClass(record.status),
    reason,
    source,
    rollout: rolloutLabel(desiredState)
  };
}

function buildRowFromLive(service: unknown, commit: unknown, image: unknown, build: unknown, revision: unknown, keyFallback: string): ServiceRow {
  const serviceRecord = asRecord(service);
  const commitRecord = asRecord(commit);
  const imageRecord = asRecord(image);
  const buildRecord = asRecord(build);
  const label = firstNonEmptyString(serviceRecord?.id, serviceRecord?.serviceId) ?? "cloud-api";
  const actualCommit = firstNonEmptyString(commitRecord?.id, revision);
  const builtAt = firstNonEmptyString(buildRecord?.createdAt);
  const tag = firstNonEmptyString(imageRecord?.tag);
  const reason = firstNonEmptyString(buildRecord?.unavailableReason);
  return {
    key: label ?? keyFallback,
    label,
    serviceId: label,
    commitShort: shortNullable(actualCommit, 12),
    actualCommit,
    actualCommitShort: shortNullable(actualCommit, 12),
    envCommitShort: null,
    revisionShort: shortNullable(revision, 12),
    tag,
    envImageTag: tag,
    imageDigestShort: shortNullable(imageRecord?.digest, 18),
    builtAt,
    status: builtAt ? "ok" : serviceRecord ? "pending" : "blocked",
    reason,
    source: sourceLabel(firstNonEmptyString(buildRecord?.metadataSource), "/health/live"),
    rollout: null
  };
}

function BuildRowItem({ row }: { row: ServiceRow }): ReactElement {
  return (
    <li className="live-build-row" role="listitem" data-live-build-row={row.key}>
      <div className="live-build-row-head">
        <span className={`live-build-tone tone-${toneClass(row.status)}`} aria-hidden="true">●</span>
        <span className="live-build-service">{row.label}</span>
        <span className="live-build-time">{row.builtAt ? formatBeijingTime(row.builtAt, { withSeconds: true }) : "构建时间不可用"}</span>
      </div>
      <div className="live-build-meta">
        <span>tag {row.tag ?? "unknown"}</span>
        <span>env 镜像 {row.envImageTag ?? "unknown"}</span>
        <span>实际 commit {row.actualCommitShort ?? row.commitShort ?? "unknown"}</span>
        <span>commit {row.commitShort ?? "unknown"}</span>
        <span>env commit {row.envCommitShort ?? "unknown"}</span>
        <span>revision {row.revisionShort ?? "unknown"}</span>
        {row.imageDigestShort ? <span>digest {row.imageDigestShort}</span> : null}
        {row.source ? <span>来源 {row.source}</span> : null}
        {row.rollout ? <span>rollout {row.rollout}</span> : null}
      </div>
      {row.reason ? <p className="live-build-reason">{row.reason}</p> : null}
    </li>
  );
}

function latestSummaryText(row: ServiceRow): string {
  const time = row.builtAt ? `${formatBeijingTime(row.builtAt, { withSeconds: true })} 北京时间` : "构建时间不可用";
  return `最新镜像构建时间：${time} · ${row.label} · tag ${row.tag ?? "unknown"} · commit ${row.commitShort ?? "unknown"} · env ${row.envImageTag ?? row.envCommitShort ?? "unknown"} · actual ${row.actualCommitShort ?? "unknown"} · revision ${row.revisionShort ?? "unknown"}`;
}

function countsSummary(counts: Record<string, unknown> | null | undefined): string | null {
  if (!counts) return null;
  const total = counts.total;
  const withBuildTime = counts.withBuildTime;
  const unavailable = counts.unavailable;
  const external = counts.external;
  return `服务 ${total ?? "unknown"} 个，可见构建时间 ${withBuildTime ?? "unknown"} 个，缺失 ${unavailable ?? "unknown"} 个，外部 ${external ?? "unknown"} 个`;
}

function sourceLabel(metadataSource: string | null, healthUrl: unknown): string | null {
  const parts = [];
  if (firstNonEmptyString(healthUrl)) parts.push("live health");
  if (metadataSource) parts.push(metadataSource);
  return parts.length ? parts.join(" / ") : null;
}

function rolloutLabel(desiredState: Record<string, unknown> | null): string | null {
  if (!desiredState) return null;
  const namespace = firstNonEmptyString(desiredState.namespace);
  const profile = firstNonEmptyString(desiredState.profile);
  const replicas = desiredState.replicas;
  const source = firstNonEmptyString(desiredState.source);
  return [namespace, profile, Number.isFinite(Number(replicas)) ? `${replicas} replicas` : null, source].filter(Boolean).join(" / ") || null;
}

function envImageLabel(tag: string | null, source: unknown): string | null {
  const sourceText = firstNonEmptyString(source);
  const envFromSource = sourceText?.match(/@env:([^\s/]+)/u)?.[1] ?? null;
  return firstNonEmptyString(tag, envFromSource);
}

function shortNullable(value: unknown, length: number): string | null {
  const text = firstNonEmptyString(value);
  return text ? shortToken(text, length) : null;
}

function emptyRow(): ServiceRow {
  return {
    key: "unknown",
    label: "unknown-service",
    serviceId: null,
    commitShort: null,
    actualCommit: null,
    actualCommitShort: null,
    envCommitShort: null,
    revisionShort: null,
    tag: null,
    envImageTag: null,
    imageDigestShort: null,
    builtAt: null,
    status: "pending",
    reason: null,
    source: null,
    rollout: null
  };
}

export { formatDuration };
