import { FormEvent, useEffect, useMemo, useRef, useState } from 'react';
import type { DashboardSnapshot, ProxyServiceRecord, SystemSettings, UpdateSystemInput } from './shared/contracts';
import type { PanelLanguage, PanelPreferences, PanelTheme } from './lib/panelPreferences';
import { getPanelText, getThemeLabel } from './lib/panelText';
import { getProtocolForCommand, validateSystemInput } from './shared/validation';

interface SystemTabProps {
  snapshot: DashboardSnapshot;
  preferences: PanelPreferences;
  onPreferencesChange: (next: PanelPreferences) => void;
  onSaveSystem: (input: UpdateSystemInput) => Promise<void>;
}

export default function SystemTab({
  snapshot,
  preferences,
  onPreferencesChange,
  onSaveSystem,
}: SystemTabProps) {
  const [draft, setDraft] = useState<UpdateSystemInput>(() => cloneSystemSettings(snapshot.system));
  const [error, setError] = useState('');
  const [isSaving, setIsSaving] = useState(false);
  const [removeServiceId, setRemoveServiceId] = useState<string | null>(null);
  const lastAppliedSystemKey = useRef(serializeSystemSettings(cloneSystemSettings(snapshot.system)));
  const text = getPanelText(preferences.language);

  useEffect(() => {
    const incomingDraft = cloneSystemSettings(snapshot.system);
    const incomingKey = serializeSystemSettings(incomingDraft);
    const draftKey = serializeSystemSettings(draft);

    if (incomingKey === lastAppliedSystemKey.current) {
      return;
    }

    if (draftKey === lastAppliedSystemKey.current || draftKey === incomingKey) {
      setDraft(incomingDraft);
      setError('');
    }

    lastAppliedSystemKey.current = incomingKey;
  }, [draft, snapshot.system]);

  const linkedUsersByService = useMemo(() => {
    const result = new Map<string, string[]>();

    snapshot.userRecords.forEach((user) => {
      const usernames = result.get(user.serviceId) ?? [];
      usernames.push(user.username);
      result.set(user.serviceId, usernames);
    });

    return result;
  }, [snapshot.userRecords]);

  const removeTarget = draft.services.find((service) => service.id === removeServiceId) ?? null;
  const removeTargetUsers = removeTarget ? linkedUsersByService.get(removeTarget.id) ?? [] : [];

  const updateService = (serviceId: string, updater: (service: ProxyServiceRecord) => ProxyServiceRecord) => {
    setDraft((current) => ({
      ...current,
      services: current.services.map((service) => (service.id === serviceId ? updater(service) : service)),
    }));
  };

  const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    setIsSaving(true);
    setError('');

    try {
      const nextServiceIds = new Set(draft.services.map((service) => service.id));
      const remainingUsers = snapshot.userRecords.filter((user) => nextServiceIds.has(user.serviceId));
      const validated = validateSystemInput(draft, remainingUsers);
      await onSaveSystem(validated);
    } catch (submitError) {
      setError(submitError instanceof Error ? submitError.message : 'Unable to save system settings.');
    } finally {
      setIsSaving(false);
    }
  };

  return (
    <>
      <form className="system-editor" onSubmit={handleSubmit}>
        <section className="page-grid single-column system-grid">
          <article className="panel-card">
            <div className="card-header">
              <h2>{text.settings.panelTitle}</h2>
            </div>
            <div className="panel-settings-grid">
              <label className="field-group panel-settings-wide">
                <span>{text.settings.proxyHost}</span>
                <input
                  value={draft.publicHost}
                  onChange={(event) =>
                    setDraft((current) => ({
                      ...current,
                      publicHost: event.target.value,
                    }))
                  }
                />
              </label>
              <label className="field-group compact-field">
                <span>{text.common.language}</span>
                <select
                  value={preferences.language}
                  onChange={(event) =>
                    onPreferencesChange({
                      ...preferences,
                      language: event.target.value as PanelLanguage,
                    })
                  }
                >
                  <option value="en">{text.common.english}</option>
                  <option value="ru">{text.common.russian}</option>
                </select>
              </label>
              <label className="field-group compact-field">
                <span>{text.common.theme}</span>
                <select
                  value={preferences.theme}
                  onChange={(event) =>
                    onPreferencesChange({
                      ...preferences,
                      theme: event.target.value as PanelTheme,
                    })
                  }
                >
                  <option value="light">{getThemeLabel(preferences.language, 'light')}</option>
                  <option value="dark">{getThemeLabel(preferences.language, 'dark')}</option>
                  <option value="system">{getThemeLabel(preferences.language, 'system')}</option>
                </select>
              </label>
            </div>
          </article>

          <article className="panel-card">
            <div className="card-header">
              <h2>{text.settings.title}</h2>
              <button
                type="button"
                className="button-secondary"
                onClick={() =>
                  setDraft((current) => ({
                    ...current,
                    services: [...current.services, createServiceDraft(current.services)],
                  }))
                }
              >
                {text.common.addService}
              </button>
            </div>
            <div className="service-editor-list">
              {draft.services.map((service, index) => (
                <section key={service.id} className="service-editor-row">
                  <div className="service-editor-header">
                    <div>
                      <strong>
                        {text.settings.serviceLabel} {index + 1}
                      </strong>
                      <p>{service.id}</p>
                    </div>
                    <button
                      type="button"
                      className="button-secondary button-small"
                      onClick={() => setRemoveServiceId(service.id)}
                    >
                      {text.common.remove}
                    </button>
                  </div>
                  <div className="service-editor-grid">
                    <label className="field-group">
                      {text.settings.name}
                      <input
                        value={service.name}
                        onChange={(event) =>
                          updateService(service.id, (current) => ({ ...current, name: event.target.value }))
                        }
                      />
                    </label>
                    <label className="field-group">
                      {text.settings.port}
                      <input
                        inputMode="numeric"
                        value={String(service.port)}
                        onChange={(event) =>
                          updateService(service.id, (current) => ({
                            ...current,
                            port: Number(event.target.value),
                          }))
                        }
                      />
                    </label>
                    <label className="field-group">
                      {text.settings.serviceType}
                      <select
                        value={service.command}
                        onChange={(event) =>
                          updateService(service.id, (current) => {
                            const command = event.target.value as ProxyServiceRecord['command'];
                            return {
                              ...current,
                              command,
                              protocol: getProtocolForCommand(command),
                            };
                          })
                        }
                      >
                        <option value="socks">{text.settings.typeSocks}</option>
                        <option value="proxy">{text.settings.typeProxy}</option>
                      </select>
                    </label>
                    <label className="field-group field-span-2">
                      {text.settings.description}
                      <input
                        value={service.description}
                        onChange={(event) =>
                          updateService(service.id, (current) => ({
                            ...current,
                            description: event.target.value,
                          }))
                        }
                      />
                    </label>
                  </div>
                  <div className="toggle-row">
                    <label className="toggle-check">
                      <input
                        type="checkbox"
                        checked={service.enabled}
                        onChange={(event) =>
                          updateService(service.id, (current) => ({
                            ...current,
                            enabled: event.target.checked,
                          }))
                        }
                      />
                      {text.common.enabled}
                    </label>
                    <label className="toggle-check">
                      <input
                        type="checkbox"
                        checked={service.assignable}
                        onChange={(event) =>
                          updateService(service.id, (current) => ({
                            ...current,
                            assignable: event.target.checked,
                          }))
                        }
                      />
                      {text.common.assignable}
                    </label>
                  </div>
                </section>
              ))}
            </div>
            {error ? <p className="form-error">{error}</p> : null}
            <div className="system-actions">
              <button
                type="button"
                className="button-secondary"
                onClick={() => {
                  setDraft(cloneSystemSettings(snapshot.system));
                  lastAppliedSystemKey.current = serializeSystemSettings(cloneSystemSettings(snapshot.system));
                  setError('');
                }}
              >
                {text.common.reset}
              </button>
              <button type="submit" disabled={isSaving}>
                {isSaving ? `${text.common.save}...` : text.common.saveSettings}
              </button>
            </div>
          </article>

          <article className="panel-card wide-card">
            <div className="card-header">
              <h2>{text.settings.generatedConfig}</h2>
            </div>
            <pre>{snapshot.system.previewConfig}</pre>
          </article>
        </section>
      </form>

      {removeTarget ? (
        <div className="modal-backdrop" role="presentation" onClick={() => setRemoveServiceId(null)}>
          <section
            aria-labelledby="remove-service-title"
            aria-modal="true"
            className="modal-card confirm-card"
            role="dialog"
            onClick={(event) => event.stopPropagation()}
          >
            <div className="modal-header">
              <h2 id="remove-service-title">{text.settings.serviceRemoveTitle}</h2>
            </div>
            <p className="confirm-copy">
              <strong>{removeTarget.name}</strong>{' '}
              {removeTargetUsers.length > 0 ? text.settings.removeWarningUsers : text.settings.removeWarningNone}
            </p>
            {removeTargetUsers.length > 0 ? (
              <p className="confirm-copy">
                {text.settings.removeWarningCount} {removeTargetUsers.join(', ')}
              </p>
            ) : null}
            <div className="modal-actions">
              <button type="button" className="button-secondary" onClick={() => setRemoveServiceId(null)}>
                {text.common.cancel}
              </button>
              <button
                type="button"
                className="button-danger"
                onClick={() => {
                  setDraft((current) => ({
                    ...current,
                    services: current.services.filter((service) => service.id !== removeTarget.id),
                  }));
                  setRemoveServiceId(null);
                }}
              >
                {text.common.remove}
              </button>
            </div>
          </section>
        </div>
      ) : null}
    </>
  );
}

function cloneSystemSettings(system: SystemSettings): UpdateSystemInput {
  return {
    publicHost: system.publicHost,
    configMode: system.configMode,
    reloadMode: system.reloadMode,
    storageMode: system.storageMode,
    services: system.services.map((service) => ({ ...service })),
  };
}

function createServiceDraft(existingServices: ProxyServiceRecord[]): ProxyServiceRecord {
  const usedPorts = new Set(existingServices.map((service) => service.port));
  let port = 1080;

  while (usedPorts.has(port) && port < 65535) {
    port += 1;
  }

  return {
    id: `service-${Math.random().toString(36).slice(2, 8)}`,
    name: `Service ${existingServices.length + 1}`,
    command: 'socks',
    protocol: 'socks5',
    description: 'Additional SOCKS5 entrypoint managed from the panel.',
    port,
    enabled: true,
    assignable: true,
  };
}

function serializeSystemSettings(system: UpdateSystemInput): string {
  return JSON.stringify(system);
}
