import {
  Suspense,
  useEffect,
  useMemo,
  useState,
  type ComponentType,
} from "react";
import {
  Check,
  ChevronDown,
  ChevronRight,
  Clipboard,
  Loader2,
  Plus,
} from "lucide-react";
import { useTranslation } from "react-i18next";

import { channelUiContribution } from "@/channel-plugins/registry";
import type { ChannelPluginConnectFlowProps } from "@/channel-plugins/types";
import { ToggleButton } from "@/components/settings/ToggleButton";
import {
  type ChannelProviderPreset,
  type ChannelSetupPresentation,
} from "@/components/settings/channels/catalog";
import {
  CredentialForm,
  channelValuesForSubmit,
  defaultChannelFieldValues,
} from "@/components/settings/channels/CredentialForm";
import {
  ChannelLogo,
  ChannelRuntimeError,
  ChannelStatusBadge,
  channelDescription,
  channelRequirements,
  channelSetup,
  channelStatusLabel,
  channelToggleChecked,
  localizedChannelDisplayName,
} from "@/components/settings/channels/ChannelIdentity";
import {
  ChannelProviderPresets,
  ChannelSetupActions,
  ChannelSetupLinks,
  ChannelSetupSteps,
  ChannelValidationBadge,
  ChannelValidationChecks,
  ChannelValidationDetails,
} from "@/components/settings/channels/ChannelSetupParts";
import { ChannelInstancesPanel } from "@/components/settings/channels/ChannelInstancesPanel";
import { Button } from "@/components/ui/button";
import {
  configureChannel,
  validateChannel,
} from "@/lib/api";
import { copyTextToClipboard } from "@/lib/clipboard";
import type {
  ChannelValidationPayload,
  NanobotFeatureInfo,
  NanobotFeaturesPayload,
} from "@/lib/types";
import { cn } from "@/lib/utils";
import { useClient } from "@/providers/ClientProvider";

export function ChannelCatalogRow({
  feature,
  selected,
  showBrandLogos,
  onSelect,
}: {
  feature: NanobotFeatureInfo;
  selected: boolean;
  showBrandLogos: boolean;
  onSelect: () => void;
}) {
  const { t } = useTranslation();
  const tx = (key: string, fallback: string) => t(key, { defaultValue: fallback });
  const displayName = localizedChannelDisplayName(feature, t);

  return (
    <button
      type="button"
      aria-label={t("settings.channels.selectChannel", {
        name: displayName,
        defaultValue: "View {{name}} settings",
      })}
      aria-pressed={selected}
      onClick={onSelect}
      className={cn(
        "group flex w-full min-w-0 items-center gap-3 rounded-control px-3 py-3 text-left transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border/80",
        selected ? "bg-background" : "hover:bg-muted",
      )}
    >
      <ChannelLogo feature={feature} showBrandLogos={showBrandLogos} />
      <div className="min-w-0 flex-1">
        <h3 className="truncate text-[14px] font-semibold leading-5 text-foreground">
          {displayName}
        </h3>
        <p className="mt-0.5 truncate text-[12.5px] leading-5 text-muted-foreground">
          {channelDescription(feature, t)}
        </p>
      </div>
      <div className="flex shrink-0 items-center gap-2">
        <ChannelStatusBadge status={feature.runtime_status}>
          {channelStatusLabel(feature, tx)}
        </ChannelStatusBadge>
        <ChevronRight
          className={cn(
            "h-4 w-4 shrink-0 text-muted-foreground transition-transform",
            selected && "translate-x-0.5 text-foreground",
          )}
          aria-hidden
        />
      </div>
    </button>
  );
}

export function ChannelSetupPanel({
  token,
  feature,
  actionKey,
  chatAppsDocsUrl,
  showBrandLogos,
  onAction,
  onFeaturesUpdate,
}: {
  token: string;
  feature: NanobotFeatureInfo;
  actionKey: string | null;
  chatAppsDocsUrl?: string;
  showBrandLogos: boolean;
  onAction: (action: "enable" | "disable", name: string) => void;
  onFeaturesUpdate: (payload: NanobotFeaturesPayload) => void;
}) {
  const { t, i18n } = useTranslation();
  const tx = (key: string, fallback: string) => t(key, { defaultValue: fallback });
  const displayName = localizedChannelDisplayName(feature, t);
  const [connectRequestId, setConnectRequestId] = useState(0);
  const uiContribution = channelUiContribution(feature.name, feature.webui);
  const PluginPanel = uiContribution?.Panel;
  if (PluginPanel) {
    return (
      <Suspense fallback={<ChannelPluginLoading />}>
        <PluginPanel
          token={token}
          feature={feature}
          actionKey={actionKey}
          showBrandLogos={showBrandLogos}
          chatAppsDocsUrl={chatAppsDocsUrl}
          onAction={onAction}
          onFeaturesUpdate={onFeaturesUpdate}
        />
      </Suspense>
    );
  }
  if (feature.instances !== undefined) {
    return (
      <ChannelInstancesPanel
        feature={feature}
        showBrandLogos={showBrandLogos}
        chatAppsDocsUrl={chatAppsDocsUrl}
        onFeaturesUpdate={onFeaturesUpdate}
      />
    );
  }
  const enableBusy = actionKey === `enable:${feature.name}`;
  const disableBusy = actionKey === `disable:${feature.name}`;
  const missingSupport = feature.enabled && !feature.installed;
  const alwaysEnabled = feature.capabilities?.includes("always_enabled") ?? false;
  const channelChecked = alwaysEnabled || channelToggleChecked(feature);
  const channelBusy = enableBusy || disableBusy;
  const setup = channelSetup(feature, i18n.resolvedLanguage ?? i18n.language);
  const needsSetupBeforeEnable =
    !channelChecked
    && feature.configured === false
    && !(uiContribution?.canConnectBeforeConfigured && setup.mode === "connect");
  const channelToggleDisabled =
    alwaysEnabled
    || channelBusy
    || needsSetupBeforeEnable
    || (!feature.install_supported && !feature.installed && !feature.enabled);
  const installSupportLabel = tx("settings.nanobotFeatures.installSupport", "Install support");
  const toggleAriaLabel = t("settings.channels.toggleChannel", {
    name: displayName,
    defaultValue: "{{name}} channel",
  });

  return (
    <aside className="min-h-full rounded-panel bg-settings-surface p-5">
      <div className="flex items-start justify-between gap-4">
        <div className="flex min-w-0 items-start gap-3">
          <ChannelLogo feature={feature} showBrandLogos={showBrandLogos} />
          <div className="min-w-0 flex-1">
            <h3 className="truncate text-[18px] font-semibold leading-6 text-foreground">
              {displayName}
            </h3>
            <p className="mt-1 text-[13px] leading-5 text-muted-foreground">
              {channelDescription(feature, t)}
            </p>
            {missingSupport && feature.install_supported ? (
              <Button
                type="button"
                size="sm"
                variant="secondary"
                disabled={enableBusy}
                onClick={() => onAction("enable", feature.name)}
                className="mt-2 h-8 rounded-full px-3 text-[12px] font-semibold"
              >
                {enableBusy ? (
                  <Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" aria-hidden />
                ) : (
                  <Plus className="mr-1.5 h-3.5 w-3.5" aria-hidden />
                )}
                {installSupportLabel}
              </Button>
            ) : null}
          </div>
        </div>
        <div className="flex shrink-0 items-center gap-2 pt-1">
          <ChannelStatusBadge status={feature.runtime_status}>
            {channelStatusLabel(feature, tx)}
          </ChannelStatusBadge>
          {channelBusy ? (
            <Loader2 className="h-3.5 w-3.5 animate-spin text-muted-foreground" aria-hidden />
          ) : null}
          <ToggleButton
            checked={channelChecked}
            disabled={channelToggleDisabled}
            ariaLabel={toggleAriaLabel}
            label={channelChecked ? tx("settings.values.on", "On") : tx("settings.values.off", "Off")}
            onChange={(checked) => {
              if (
                uiContribution?.canConnectBeforeConfigured
                && checked
                && !channelChecked
                && feature.configured === false
              ) {
                setConnectRequestId((current) => current + 1);
                return;
              }
              onAction(checked ? "enable" : "disable", feature.name);
            }}
          />
        </div>
      </div>

      <ChannelRuntimeError message={feature.runtime_error} className="mt-4" />

      <ChannelSetupSurface
        token={token}
        feature={feature}
        setup={setup}
        chatAppsDocsUrl={chatAppsDocsUrl}
        connectRequestId={connectRequestId}
        ConnectFlow={uiContribution?.ConnectFlow}
        onFeaturesUpdate={onFeaturesUpdate}
      />
    </aside>
  );
}

function ChannelSetupSurface({
  token,
  feature,
  setup,
  chatAppsDocsUrl,
  connectRequestId,
  ConnectFlow,
  onFeaturesUpdate,
}: {
  token: string;
  feature: NanobotFeatureInfo;
  setup: ChannelSetupPresentation;
  chatAppsDocsUrl?: string;
  connectRequestId: number;
  ConnectFlow?: ComponentType<ChannelPluginConnectFlowProps>;
  onFeaturesUpdate: (payload: NanobotFeaturesPayload) => void;
}) {
  const { client } = useClient();
  const { t } = useTranslation();
  const tx = (key: string, fallback: string) => t(key, { defaultValue: fallback });
  const [notice, setNotice] = useState<string | null>(null);
  const [saving, setSaving] = useState(false);
  const [validating, setValidating] = useState(false);
  const [validation, setValidation] = useState<ChannelValidationPayload | null>(null);
  const [visibleSecrets, setVisibleSecrets] = useState<Record<string, boolean>>({});
  const [touchedFields, setTouchedFields] = useState<Set<string>>(() => new Set());
  const configValuesKey = JSON.stringify(feature.config_values ?? {});
  const configuredFields = useMemo(
    () => new Set(feature.configured_fields ?? []),
    [feature.configured_fields],
  );
  const mode = setup.mode ?? "credentials";
  const fields = setup.fields ?? [];
  const requiredFields = fields.filter((field) => !field.optional);
  const primaryFields = requiredFields.length ? requiredFields : fields.slice(0, 1);
  const optionalFields = fields.filter((field) => field.optional);
  const manualFields = setup.manualFields ?? [];
  const advancedFields = mode === "connect" ? manualFields : optionalFields;
  const editableFields = mode === "credentials" ? fields : mode === "connect" ? manualFields : [];
  const hasAdvanced = advancedFields.length > 0;
  const requirements = channelRequirements(feature, t);
  const summary = setup.summary ?? tx(
    "settings.channels.setupSummary",
    "Enable only turns on nanobot support. Add the platform credentials, then restart nanobot.",
  );
  const [fieldValues, setFieldValues] = useState<Record<string, string>>(() =>
    defaultChannelFieldValues(editableFields, feature.config_values),
  );

  useEffect(() => {
    setNotice(null);
    setVisibleSecrets({});
    setSaving(false);
    setValidating(false);
    setValidation(null);
    setTouchedFields(new Set());
    setFieldValues(defaultChannelFieldValues(editableFields, feature.config_values));
  }, [configValuesKey, feature.name]);

  const toggleSecret = (key: string) => {
    setVisibleSecrets((current) => ({ ...current, [key]: !current[key] }));
  };

  const setFieldValue = (key: string, value: string) => {
    setFieldValues((current) => ({ ...current, [key]: value }));
    setTouchedFields((current) => new Set(current).add(key));
  };

  const applyPreset = (preset: ChannelProviderPreset) => {
    setFieldValues((current) => ({ ...current, ...preset.values }));
    setTouchedFields((current) => {
      const next = new Set(current);
      for (const key of Object.keys(preset.values)) next.add(key);
      return next;
    });
  };

  const copyCommand = () => {
    if (!setup.command) return;
    void copyTextToClipboard(setup.command).then((ok) => {
      setNotice(
        ok
          ? tx("settings.channels.commandCopied", "Command copied.")
          : tx("settings.channels.commandCopyFailed", "Could not copy command."),
      );
    });
  };

  const saveCredentialSettings = async () => {
    setSaving(true);
    setValidating(true);
    setNotice(null);
    const values = channelValuesForSubmit(fields, fieldValues, touchedFields);
    try {
      const validationPayload = await validateChannel(client, feature.name, values);
      setValidation(validationPayload);
      if (!validationPayload.can_enable) {
        setNotice(
          validationPayload.message
            ?? tx("settings.channels.validationFailed", "Check the required setup before enabling."),
        );
        return;
      }
      const payload = await configureChannel(
        client,
        feature.name,
        values,
        { enable: true },
      );
      if (payload.nanobot_features) {
        onFeaturesUpdate(payload.nanobot_features);
      }
      setNotice(tx("settings.channels.checkedAndEnabled", "Checked and enabled."));
    } catch (err) {
      setNotice((err as Error).message);
    } finally {
      setSaving(false);
      setValidating(false);
    }
  };

  const checkCurrentSettings = async () => {
    setValidating(true);
    setNotice(null);
    try {
      const payload = await validateChannel(
        client,
        feature.name,
        channelValuesForSubmit(fields, fieldValues, touchedFields),
      );
      setValidation(payload);
      if (payload.message) setNotice(payload.message);
    } catch (err) {
      setNotice((err as Error).message);
    } finally {
      setValidating(false);
    }
  };

  const primaryActionLabel = channelToggleChecked(feature)
    ? tx("settings.channels.checkConnection", "Check connection")
    : tx("settings.channels.checkAndEnable", "Check and enable");

  return (
    <form
      className="mt-5 space-y-5"
      onSubmit={(event) => {
        event.preventDefault();
        if (mode === "credentials") void saveCredentialSettings();
      }}
    >
      <section>
        <div className="flex flex-wrap items-center justify-between gap-2">
          <div className="text-[13px] font-semibold text-foreground">
            {tx("settings.channels.requiredSetup", "Required setup")}
          </div>
          <div className="flex max-w-full flex-wrap justify-end gap-2">
            {mode !== "webui" ? (
              <ChannelValidationBadge
                validation={validation}
                validating={validating}
                feature={feature}
              />
            ) : null}
            {mode === "webui" ? (
              <span className="inline-flex items-center gap-1 rounded-full bg-emerald-500/10 px-2.5 py-1 text-[11.5px] font-medium text-emerald-700 dark:text-emerald-200">
                <Check className="h-3.5 w-3.5" aria-hidden />
                {tx("settings.channels.managedByWebui", "Managed by WebUI")}
              </span>
            ) : null}
          </div>
        </div>
        <p className="mt-1 text-[12.5px] leading-5 text-muted-foreground">{requirements}</p>

        <p className="mt-3 text-[12.5px] leading-5 text-muted-foreground">{summary}</p>
        <ChannelValidationDetails validation={validation} />
        <ChannelSetupLinks feature={feature} setup={setup} chatAppsDocsUrl={chatAppsDocsUrl} />
        <ChannelSetupActions feature={feature} setup={setup} onNotice={setNotice} />

        {mode === "connect" && ConnectFlow ? (
          <Suspense fallback={<ChannelPluginLoading compact />}>
            <ConnectFlow
              token={token}
              feature={feature}
              idleLabel={setup.primaryActionLabel ?? tx("settings.channels.connect", "Connect")}
              connectRequestId={connectRequestId}
              onFeaturesUpdate={onFeaturesUpdate}
            />
          </Suspense>
        ) : mode === "connect" ? (
          <>
            <div className="mt-3 flex flex-wrap justify-end gap-2">
              <Button
                type="button"
                size="sm"
                variant="secondary"
                className="h-8 rounded-full bg-background/80 px-3 text-[12px] font-semibold hover:bg-background"
                onClick={() =>
                  setNotice(
                    tx(
                      "settings.channels.connectPreview",
                      "The in-browser connect flow is next. For now, run the command below.",
                    ),
                  )
                }
              >
                {setup.primaryActionLabel ?? tx("settings.channels.connect", "Connect")}
              </Button>
              {setup.command ? (
                <Button
                  type="button"
                  size="sm"
                  variant="secondary"
                  className="h-8 rounded-full px-3 text-[12px] font-semibold"
                  onClick={copyCommand}
                >
                  <Clipboard className="mr-1.5 h-3.5 w-3.5" aria-hidden />
                  {tx("settings.channels.copyCommand", "Copy command")}
                </Button>
              ) : null}
            </div>
            {setup.command ? (
              <code className="mt-3 block rounded-control border border-border/50 bg-muted/45 px-2.5 py-2 font-mono text-[11px] leading-5 text-foreground">
                {setup.command}
              </code>
            ) : null}
          </>
        ) : mode === "credentials" ? (
          <>
            {setup.presets?.length ? (
              <ChannelProviderPresets
                presets={setup.presets}
                onApply={applyPreset}
              />
            ) : null}
            {primaryFields.length ? (
              <CredentialForm
                fields={primaryFields}
                values={fieldValues}
                configuredFields={configuredFields}
                visibleSecrets={visibleSecrets}
                onChange={setFieldValue}
                onToggleSecret={toggleSecret}
              />
            ) : null}
            <div className="mt-3 flex flex-wrap justify-end gap-2">
              <Button
                type="submit"
                size="sm"
                variant="secondary"
                className="h-8 rounded-full bg-background/80 px-3 text-[12px] font-semibold hover:bg-background"
                disabled={saving}
              >
                {saving || validating ? (
                  <Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" aria-hidden />
                ) : null}
                {primaryActionLabel}
              </Button>
              {feature.configured || validation ? (
                <Button
                  type="button"
                  size="sm"
                  variant="ghost"
                  className="h-8 rounded-full px-3 text-[12px] font-semibold"
                  onClick={() => void checkCurrentSettings()}
                  disabled={saving || validating}
                >
                  {tx("settings.channels.checkOnly", "Check only")}
                </Button>
              ) : null}
            </div>
          </>
        ) : null}
      </section>

      {notice ? (
        <div
          role="status"
          className="rounded-control bg-muted/55 px-3 py-2.5 text-[12px] leading-5 text-muted-foreground"
        >
          {notice}
        </div>
      ) : null}

      {setup.steps.length ? (
        <ChannelSetupSteps steps={setup.steps} tryIt={setup.tryIt} />
      ) : null}

      {validation?.checks.length ? <ChannelValidationChecks validation={validation} /> : null}

      {hasAdvanced ? (
        <details className="group text-[12px] leading-5 text-muted-foreground">
          <summary className="cursor-pointer list-none text-[12px] font-semibold text-foreground">
            <span className="inline-flex items-center gap-1.5">
              {tx("settings.channels.advanced", "Advanced")}
              <ChevronDown className="h-3.5 w-3.5 transition-transform group-open:rotate-180" aria-hidden />
            </span>
          </summary>
          {advancedFields.length ? (
            <div className="mt-3">
              <CredentialForm
                fields={advancedFields}
                values={fieldValues}
                configuredFields={configuredFields}
                visibleSecrets={visibleSecrets}
                onChange={setFieldValue}
                onToggleSecret={toggleSecret}
                compact
              />
            </div>
          ) : null}
        </details>
      ) : null}
    </form>
  );
}

function ChannelPluginLoading({ compact = false }: { compact?: boolean }) {
  const { t } = useTranslation();
  return (
    <div
      role="status"
      className={cn(
        "flex items-center justify-center gap-2 text-sm text-muted-foreground",
        compact ? "min-h-12" : "min-h-48",
      )}
    >
      <Loader2 className="h-4 w-4 animate-spin motion-reduce:animate-none" aria-hidden />
      {t("settings.status.loading")}
    </div>
  );
}
