import { useState, useMemo, useEffect } from 'react';
import {
  Badge,
  Button,
  Input,
  MonoText,
  SectionHeader,
  Tag,
  Toggle,
  InlineEdit,
  ConfirmDialog,
  SplitPane,
  EntityList,
  useToast,
} from '@cameleer/design-system';
import {
  useEnvironments,
  useCreateEnvironment,
  useUpdateEnvironment,
  useDeleteEnvironment,
  useUpdateDefaultContainerConfig,
  useUpdateJarRetention,
} from '../../api/queries/admin/environments';
import type { Environment } from '../../api/queries/admin/environments';
import { ENV_COLORS, envColorVar, type EnvColor } from '../../components/env-colors';
import { Check } from 'lucide-react';
import { PageLoader } from '../../components/PageLoader';
import styles from './UserManagement.module.css';
import sectionStyles from '../../styles/section-card.module.css';

function slugify(name: string): string {
  return name
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '')
    .substring(0, 100);
}

export default function EnvironmentsPage() {
  const { toast } = useToast();
  const { data: environments = [], isLoading } = useEnvironments();

  const [search, setSearch] = useState('');
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const [creating, setCreating] = useState(false);
  const [deleteTarget, setDeleteTarget] = useState<Environment | null>(null);

  // Create form state
  const [newSlug, setNewSlug] = useState('');
  const [newDisplayName, setNewDisplayName] = useState('');
  const [newProduction, setNewProduction] = useState(false);

  useEffect(() => {
    setNewSlug(slugify(newDisplayName));
  }, [newDisplayName]);

  // Mutations
  const createEnv = useCreateEnvironment();
  const updateEnv = useUpdateEnvironment();
  const deleteEnv = useDeleteEnvironment();
  const updateDefaults = useUpdateDefaultContainerConfig();
  const updateRetention = useUpdateJarRetention();

  const selected = useMemo(
    () => environments.find((e) => e.id === selectedId) ?? null,
    [environments, selectedId],
  );

  const filtered = useMemo(() => {
    if (!search) return environments;
    const q = search.toLowerCase();
    return environments.filter(
      (e) =>
        e.slug.toLowerCase().includes(q) ||
        e.displayName.toLowerCase().includes(q),
    );
  }, [environments, search]);

  const isDefault = selected?.slug === 'default';

  const duplicateSlug =
    newSlug.trim() !== '' &&
    environments.some((e) => e.slug.toLowerCase() === newSlug.trim().toLowerCase());

  async function handleCreate() {
    if (!newSlug.trim() || !newDisplayName.trim()) return;
    try {
      await createEnv.mutateAsync({
        slug: newSlug.trim(),
        displayName: newDisplayName.trim(),
        production: newProduction,
      });
      toast({ title: 'Environment created', description: newSlug.trim(), variant: 'success' });
      setCreating(false);
      setNewSlug('');
      setNewDisplayName('');
      setNewProduction(false);
    } catch {
      toast({ title: 'Failed to create environment', variant: 'error', duration: 86_400_000 });
    }
  }

  async function handleDelete() {
    if (!deleteTarget) return;
    try {
      await deleteEnv.mutateAsync(deleteTarget.slug);
      toast({ title: 'Environment deleted', description: deleteTarget.slug, variant: 'warning' });
      if (selectedId === deleteTarget.id) setSelectedId(null);
      setDeleteTarget(null);
    } catch {
      toast({ title: 'Failed to delete environment', variant: 'error', duration: 86_400_000 });
      setDeleteTarget(null);
    }
  }

  async function handleRename(newName: string) {
    if (!selected) return;
    try {
      await updateEnv.mutateAsync({
        slug: selected.slug,
        displayName: newName,
        production: selected.production,
        enabled: selected.enabled,
        color: selected.color,
      });
      toast({ title: 'Environment renamed', variant: 'success' });
    } catch {
      toast({ title: 'Failed to rename', variant: 'error', duration: 86_400_000 });
    }
  }

  async function handleToggleProduction(value: boolean) {
    if (!selected) return;
    try {
      await updateEnv.mutateAsync({
        slug: selected.slug,
        displayName: selected.displayName,
        production: value,
        enabled: selected.enabled,
        color: selected.color,
      });
      toast({ title: value ? 'Marked as production' : 'Marked as non-production', variant: 'success' });
    } catch {
      toast({ title: 'Failed to update', variant: 'error', duration: 86_400_000 });
    }
  }

  async function handleToggleEnabled(value: boolean) {
    if (!selected) return;
    try {
      await updateEnv.mutateAsync({
        slug: selected.slug,
        displayName: selected.displayName,
        production: selected.production,
        enabled: value,
        color: selected.color,
      });
      toast({ title: value ? 'Environment enabled' : 'Environment disabled', variant: 'success' });
    } catch {
      toast({ title: 'Failed to update', variant: 'error', duration: 86_400_000 });
    }
  }

  async function handleColorChange(color: EnvColor) {
    if (!selected || selected.color === color) return;
    try {
      await updateEnv.mutateAsync({
        slug: selected.slug,
        displayName: selected.displayName,
        production: selected.production,
        enabled: selected.enabled,
        color,
      });
      toast({ title: 'Environment color updated', variant: 'success' });
    } catch {
      toast({ title: 'Failed to update color', variant: 'error', duration: 86_400_000 });
    }
  }

  if (isLoading) return <PageLoader />;

  return (
    <>
      <SplitPane
        list={
          <>
            {creating && (
              <div className={styles.createForm}>
                <Input
                  placeholder="Display name *"
                  value={newDisplayName}
                  onChange={(e) => setNewDisplayName(e.target.value)}
                />
                <MonoText size="sm">{newSlug || '...'}</MonoText>
                {duplicateSlug && (
                  <span className={styles.errorText}>Slug already exists</span>
                )}
                <label className={styles.securityRow}>
                  <Toggle checked={newProduction} onChange={() => setNewProduction(!newProduction)} />
                  Production environment
                </label>
                <div className={styles.createFormActions}>
                  <Button size="sm" variant="ghost" onClick={() => setCreating(false)}>
                    Cancel
                  </Button>
                  <Button
                    size="sm"
                    variant="primary"
                    onClick={handleCreate}
                    loading={createEnv.isPending}
                    disabled={!newSlug.trim() || !newDisplayName.trim() || duplicateSlug}
                  >
                    Create
                  </Button>
                </div>
              </div>
            )}

            <EntityList
              items={filtered}
              renderItem={(env) => (
                <>
                  <EnvColoredAvatar name={env.displayName} color={env.color} size="sm" />
                  <div className={styles.entityInfo}>
                    <div className={styles.entityName}>{env.displayName}</div>
                    <div className={styles.entityMeta}>
                      {env.slug}
                    </div>
                    <div className={styles.entityTags}>
                      {env.production && <Badge label="PROD" color="error" />}
                      {!env.production && <Badge label="NON-PROD" color="auto" />}
                      {!env.enabled && <Badge label="DISABLED" color="warning" />}
                    </div>
                  </div>
                </>
              )}
              getItemId={(env) => env.id}
              selectedId={selectedId ?? undefined}
              onSelect={setSelectedId}
              searchPlaceholder="Search environments..."
              onSearch={setSearch}
              addLabel="+ Add environment"
              onAdd={() => setCreating(true)}
              emptyMessage="No environments match your search"
            />
          </>
        }
        detail={
          selected ? (
            <>
              <div className={styles.detailHeader}>
                <EnvColoredAvatar name={selected.displayName} color={selected.color} size="lg" />
                <div className={styles.detailHeaderInfo}>
                  <div className={styles.detailName}>
                    {isDefault ? (
                      selected.displayName
                    ) : (
                      <InlineEdit value={selected.displayName} onSave={handleRename} />
                    )}
                  </div>
                  <div className={styles.detailEmail}>
                    {selected.slug}
                    {isDefault && ' (built-in)'}
                  </div>
                </div>
                <Button
                  size="sm"
                  variant="danger"
                  onClick={() => setDeleteTarget(selected)}
                  disabled={isDefault}
                >
                  Delete
                </Button>
              </div>

              <div className={styles.metaGrid}>
                <span className={styles.metaLabel}>ID</span>
                <MonoText size="xs">{selected.id}</MonoText>
                <span className={styles.metaLabel}>Slug</span>
                <span className={styles.metaValue}>{selected.slug}</span>
                <span className={styles.metaLabel}>Created</span>
                <span className={styles.metaValue}>
                  {new Date(selected.createdAt).toLocaleDateString()}
                </span>
              </div>

              <div className={sectionStyles.section}>
                <SectionHeader>Configuration</SectionHeader>
                <div className={styles.securitySection}>
                  <div className={styles.securityRow}>
                    <Toggle checked={selected.production} onChange={() => handleToggleProduction(!selected.production)} />
                    <span>Production environment</span>
                    {selected.production ? (
                      <Tag label="Dedicated resources" color="error" />
                    ) : (
                      <Tag label="Shared resources" color="auto" />
                    )}
                  </div>
                </div>
              </div>

              <div className={sectionStyles.section}>
                <SectionHeader>Appearance</SectionHeader>
                <p className={styles.inheritedNote}>
                  This color is shown as a 3px bar across every page while this environment is active.
                </p>
                <div role="radiogroup" aria-label="Environment color" style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
                  {ENV_COLORS.map((c) => {
                    const isSelected = selected.color === c;
                    return (
                      <button
                        key={c}
                        type="button"
                        role="radio"
                        aria-checked={isSelected}
                        aria-label={c}
                        title={c}
                        onClick={() => handleColorChange(c)}
                        style={{
                          width: 36,
                          height: 36,
                          borderRadius: '50%',
                          background: envColorVar(c),
                          border: isSelected ? '2px solid var(--text-primary)' : '1px solid var(--border-subtle)',
                          cursor: 'pointer',
                          display: 'inline-flex',
                          alignItems: 'center',
                          justifyContent: 'center',
                          color: '#fff',
                          padding: 0,
                        }}
                      >
                        {isSelected && <Check size={16} aria-hidden />}
                      </button>
                    );
                  })}
                </div>
              </div>

              <div className={sectionStyles.section}>
                <SectionHeader>Status</SectionHeader>
                <div className={styles.securitySection}>
                  <div className={styles.securityRow}>
                    <Toggle checked={selected.enabled} onChange={() => handleToggleEnabled(!selected.enabled)} />
                    <span>{selected.enabled ? 'Enabled' : 'Disabled'}</span>
                    {!selected.enabled && (
                      <Tag label="No new deployments" color="warning" />
                    )}
                  </div>
                  {!selected.enabled && (
                    <p className={styles.inheritedNote}>
                      Disabled environments do not allow new deployments. Active
                      deployments can only be started, stopped, or deleted.
                    </p>
                  )}
                </div>
              </div>

              <DefaultResourcesSection environment={selected} onSave={async (config) => {
                try {
                  await updateDefaults.mutateAsync({ slug: selected.slug, config });
                  toast({ title: 'Default resources updated', variant: 'success' });
                } catch {
                  toast({ title: 'Failed to update defaults', variant: 'error', duration: 86_400_000 });
                }
              }} saving={updateDefaults.isPending} />

              <JarRetentionSection environment={selected} onSave={async (count) => {
                try {
                  await updateRetention.mutateAsync({ slug: selected.slug, jarRetentionCount: count });
                  toast({ title: 'Retention policy updated', variant: 'success' });
                } catch {
                  toast({ title: 'Failed to update retention', variant: 'error', duration: 86_400_000 });
                }
              }} saving={updateRetention.isPending} />
            </>
          ) : null
        }
        emptyMessage="Select an environment to view details"
      />

      <ConfirmDialog
        open={deleteTarget !== null}
        onClose={() => setDeleteTarget(null)}
        onConfirm={handleDelete}
        message={`Delete environment "${deleteTarget?.displayName}"? All apps and deployments in this environment will be removed. This cannot be undone.`}
        confirmText={deleteTarget?.slug ?? ''}
        loading={deleteEnv.isPending}
      />
    </>
  );
}

// ── Env-colored Avatar ──────────────────────────────────────────────

// Custom circular initial badge filled with the environment's color. We don't
// wrap the DS `Avatar` because it picks its background from a name hash with
// no color override — we need the env color to be the dominant signal.
const ENV_AVATAR_SIZES = { sm: 24, md: 28, lg: 40 } as const;
const ENV_AVATAR_FONT = { sm: 10, md: 12, lg: 16 } as const;

function envInitials(displayName: string): string {
  const words = displayName.trim().split(/\s+/).filter(Boolean);
  if (words.length === 0) return '?';
  if (words.length === 1) return words[0].slice(0, 2).toUpperCase();
  return (words[0][0] + words[1][0]).toUpperCase();
}

function EnvColoredAvatar({ name, color, size }: {
  name: string;
  color: string | null | undefined;
  size: 'sm' | 'md' | 'lg';
}) {
  const dimension = ENV_AVATAR_SIZES[size];
  const fontSize = ENV_AVATAR_FONT[size];
  return (
    <span
      aria-label={name}
      title={name}
      style={{
        display: 'inline-flex',
        alignItems: 'center',
        justifyContent: 'center',
        width: dimension,
        height: dimension,
        borderRadius: '50%',
        background: envColorVar(color),
        color: '#fff',
        fontSize,
        fontWeight: 600,
        flexShrink: 0,
        // subtle border so the circle still reads on bg-surface when the env
        // color itself is very light (amber, green)
        border: '1px solid var(--border-subtle)',
        userSelect: 'none',
        textShadow: '0 1px 1px rgba(0,0,0,0.25)',
      }}
    >
      {envInitials(name)}
    </span>
  );
}

// ── Default Resource Limits ─────────────────────────────────────────

function DefaultResourcesSection({ environment, onSave, saving }: {
  environment: Environment;
  onSave: (config: Record<string, unknown>) => Promise<void>;
  saving: boolean;
}) {
  const defaults = environment.defaultContainerConfig ?? {};
  const [editing, setEditing] = useState(false);
  const [memoryLimit, setMemoryLimit] = useState('');
  const [memoryReserve, setMemoryReserve] = useState('');
  const [cpuRequest, setCpuRequest] = useState('');
  const [cpuLimit, setCpuLimit] = useState('');
  const [routingMode, setRoutingMode] = useState(String(defaults.routingMode ?? 'path'));
  const [routingDomain, setRoutingDomain] = useState(String(defaults.routingDomain ?? ''));
  const [serverUrl, setServerUrl] = useState(String(defaults.serverUrl ?? ''));
  const [envSslOffloading, setEnvSslOffloading] = useState(defaults.sslOffloading !== false);
  const [envRouteControl, setEnvRouteControl] = useState(defaults.routeControlEnabled !== false);
  const [envReplay, setEnvReplay] = useState(defaults.replayEnabled !== false);

  useEffect(() => {
    setMemoryLimit(String(defaults.memoryLimitMb ?? ''));
    setMemoryReserve(String(defaults.memoryReserveMb ?? ''));
    setCpuRequest(String(defaults.cpuRequest ?? ''));
    setCpuLimit(String(defaults.cpuLimit ?? ''));
    setRoutingMode(String(environment.defaultContainerConfig.routingMode ?? 'path'));
    setRoutingDomain(String(environment.defaultContainerConfig.routingDomain ?? ''));
    setServerUrl(String(environment.defaultContainerConfig.serverUrl ?? ''));
    setEnvSslOffloading(environment.defaultContainerConfig.sslOffloading !== false);
    setEnvRouteControl(environment.defaultContainerConfig.routeControlEnabled !== false);
    setEnvReplay(environment.defaultContainerConfig.replayEnabled !== false);
    setEditing(false);
  }, [environment.id]);

  function handleCancel() {
    setMemoryLimit(String(defaults.memoryLimitMb ?? ''));
    setMemoryReserve(String(defaults.memoryReserveMb ?? ''));
    setCpuRequest(String(defaults.cpuRequest ?? ''));
    setCpuLimit(String(defaults.cpuLimit ?? ''));
    setRoutingMode(String(defaults.routingMode ?? 'path'));
    setRoutingDomain(String(defaults.routingDomain ?? ''));
    setServerUrl(String(defaults.serverUrl ?? ''));
    setEnvSslOffloading(defaults.sslOffloading !== false);
    setEnvRouteControl(defaults.routeControlEnabled !== false);
    setEnvReplay(defaults.replayEnabled !== false);
    setEditing(false);
  }

  async function handleSave() {
    await onSave({
      memoryLimitMb: memoryLimit ? parseInt(memoryLimit) : null,
      memoryReserveMb: memoryReserve ? parseInt(memoryReserve) : null,
      cpuRequest: cpuRequest ? parseInt(cpuRequest) : null,
      cpuLimit: cpuLimit ? parseInt(cpuLimit) : null,
      routingMode,
      routingDomain: routingDomain || null,
      serverUrl: serverUrl || null,
      sslOffloading: envSslOffloading,
      routeControlEnabled: envRouteControl,
      replayEnabled: envReplay,
    });
    setEditing(false);
  }

  return (
    <div className={sectionStyles.section}>
      <SectionHeader>Default Resource Limits</SectionHeader>
      {editing && (
        <div className={styles.editBanner}>
          Editing resource defaults. Changes are not saved until you click Save.
        </div>
      )}
      <p className={styles.inheritedNote}>
        These defaults apply to new apps in this environment unless overridden per-app.
      </p>
      <div className={styles.metaGrid}>
        <span className={styles.metaLabel}>Memory Limit</span>
        {editing
          ? <Input value={memoryLimit} onChange={(e) => setMemoryLimit(e.target.value)} placeholder="e.g. 512" style={{ width: 100 }} />
          : <span className={styles.metaValue}>{defaults.memoryLimitMb ? `${defaults.memoryLimitMb} MB` : '—'}</span>}

        <span className={styles.metaLabel}>Memory Reserve</span>
        {editing
          ? <Input value={memoryReserve} onChange={(e) => setMemoryReserve(e.target.value)} placeholder="e.g. 256" style={{ width: 100 }} />
          : <span className={styles.metaValue}>{defaults.memoryReserveMb ? `${defaults.memoryReserveMb} MB` : '—'}</span>}

        <span className={styles.metaLabel}>CPU Request</span>
        {editing
          ? <Input value={cpuRequest} onChange={(e) => setCpuRequest(e.target.value)} placeholder="e.g. 500" style={{ width: 100 }} />
          : <span className={styles.metaValue}>{defaults.cpuRequest ? `${defaults.cpuRequest}m` : '—'}</span>}

        <span className={styles.metaLabel}>CPU Limit</span>
        {editing
          ? <Input value={cpuLimit} onChange={(e) => setCpuLimit(e.target.value)} placeholder="e.g. 1000" style={{ width: 100 }} />
          : <span className={styles.metaValue}>{defaults.cpuLimit ? `${defaults.cpuLimit}m` : '—'}</span>}

        <span className={styles.metaLabel}>Routing Mode</span>
        {editing
          ? <select value={routingMode} onChange={(e) => setRoutingMode(e.target.value)} style={{ padding: '4px 8px', border: '1px solid var(--border-subtle)', borderRadius: 4, background: 'var(--bg-surface)', color: 'var(--text-primary)', fontSize: 12 }}>
              <option value="path">Path-based</option>
              <option value="subdomain">Subdomain</option>
            </select>
          : <span className={styles.metaValue}>{routingMode === 'subdomain' ? 'Subdomain' : 'Path-based'}</span>}

        <span className={styles.metaLabel}>Routing Domain</span>
        {editing
          ? <Input value={routingDomain} onChange={(e) => setRoutingDomain(e.target.value)} placeholder="e.g. apps.example.com" style={{ width: 200 }} />
          : <span className={styles.metaValue}>{String(defaults.routingDomain || '—')}</span>}

        <span className={styles.metaLabel}>Server URL</span>
        {editing
          ? <Input value={serverUrl} onChange={(e) => setServerUrl(e.target.value)} placeholder="auto-detect" style={{ width: 200 }} />
          : <span className={styles.metaValue}>{String(defaults.serverUrl || '(global default)')}</span>}

        <span className={styles.metaLabel}>SSL Offloading</span>
        {editing
          ? <Toggle checked={envSslOffloading} onChange={() => setEnvSslOffloading(!envSslOffloading)} />
          : <span className={styles.metaValue}>{envSslOffloading ? 'Enabled' : 'Disabled'}</span>}

        <span className={styles.metaLabel}>Route Control</span>
        {editing
          ? <Toggle checked={envRouteControl} onChange={() => setEnvRouteControl(!envRouteControl)} />
          : <span className={styles.metaValue}>{envRouteControl ? 'Enabled' : 'Disabled'}</span>}

        <span className={styles.metaLabel}>Replay</span>
        {editing
          ? <Toggle checked={envReplay} onChange={() => setEnvReplay(!envReplay)} />
          : <span className={styles.metaValue}>{envReplay ? 'Enabled' : 'Disabled'}</span>}
      </div>
      <div style={{ marginTop: 8, display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
        {editing ? (
          <>
            <Button size="sm" variant="ghost" onClick={handleCancel}>Cancel</Button>
            <Button size="sm" variant="primary" onClick={handleSave} loading={saving}>Save</Button>
          </>
        ) : (
          <Button size="sm" variant="secondary" onClick={() => setEditing(true)}>Edit Defaults</Button>
        )}
      </div>
    </div>
  );
}

// ── JAR Retention Policy ────────────────────────────────────────────

function JarRetentionSection({ environment, onSave, saving }: {
  environment: Environment;
  onSave: (count: number | null) => Promise<void>;
  saving: boolean;
}) {
  const current = environment.jarRetentionCount;
  const [editing, setEditing] = useState(false);
  const [unlimited, setUnlimited] = useState(current === null);
  const [count, setCount] = useState(String(current ?? 5));

  useEffect(() => {
    setUnlimited(environment.jarRetentionCount === null);
    setCount(String(environment.jarRetentionCount ?? 5));
    setEditing(false);
  }, [environment.id]);

  function handleCancel() {
    setUnlimited(current === null);
    setCount(String(current ?? 5));
    setEditing(false);
  }

  async function handleSave() {
    await onSave(unlimited ? null : Math.max(1, parseInt(count) || 5));
    setEditing(false);
  }

  return (
    <div className={sectionStyles.section}>
      <SectionHeader>JAR Retention</SectionHeader>
      {editing && (
        <div className={styles.editBanner}>
          Editing resource defaults. Changes are not saved until you click Save.
        </div>
      )}
      <p className={styles.inheritedNote}>
        Old JAR versions are cleaned up nightly. Currently deployed versions are never deleted.
      </p>
      <div className={styles.metaGrid}>
        <span className={styles.metaLabel}>Policy</span>
        {editing ? (
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <Toggle checked={!unlimited} onChange={() => setUnlimited(!unlimited)} />
            {unlimited
              ? <span>Keep all versions (unlimited)</span>
              : <>
                  <span>Keep last</span>
                  <Input value={count} onChange={(e) => setCount(e.target.value)} style={{ width: 60 }} />
                  <span>versions</span>
                </>}
          </div>
        ) : (
          <span className={styles.metaValue}>
            {current === null ? 'Unlimited (no cleanup)' : `Keep last ${current} versions`}
          </span>
        )}
      </div>
      <div style={{ marginTop: 8, display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
        {editing ? (
          <>
            <Button size="sm" variant="ghost" onClick={handleCancel}>Cancel</Button>
            <Button size="sm" variant="primary" onClick={handleSave} loading={saving}>Save</Button>
          </>
        ) : (
          <Button size="sm" variant="secondary" onClick={() => setEditing(true)}>Edit Policy</Button>
        )}
      </div>
    </div>
  );
}
