import React, { useMemo, useState, useCallback, useEffect } from 'react';
import PanelHeader from '../ui/PanelHeader';

const SECTIONS = [
  {
    id: 'passkeys',
    label: 'Passkeys',
  },
  {
    id: 'apiTokens',
    label: 'API tokens',
  },
];

const SettingsModal = ({
  open,
  onClose,
  tokens = [],
  loading = false,
  creating = false,
  deletingId = null,
  regeneratingId = null,
  capabilitySets = [],
  capabilitySetsLoading = false,
  onRefresh,
  onCreate,
  onDelete,
  onRegenerate,
  createdToken = null,
  onDismissCreatedToken,
  passkeys = [],
  passkeysSupported = null,
  passkeysLoading = false,
  registeringPasskey = false,
  revokingPasskeyId = null,
  onRefreshPasskeys,
  onRegisterPasskey,
  onRevokePasskey,
}) => {
  const defaultSection = SECTIONS[0]?.id || 'passkeys';
  const [activeSection, setActiveSection] = useState(defaultSection);
  const [newTokenLabel, setNewTokenLabel] = useState('');
  const [newTokenExpires, setNewTokenExpires] = useState('');
  const [newTokenCapabilitySetId, setNewTokenCapabilitySetId] = useState('');
  const [formError, setFormError] = useState(null);
  const [newPasskeyNickname, setNewPasskeyNickname] = useState('');

  const handleBackdropClick = useCallback(() => {
    onClose?.();
  }, [onClose]);

  const handleInnerClick = useCallback((event) => {
    event.stopPropagation();
  }, []);

  useEffect(() => {
    if (!open) {
      setActiveSection(defaultSection);
      setNewTokenLabel('');
      setNewTokenExpires('');
      setNewTokenCapabilitySetId('');
      setFormError(null);
      setNewPasskeyNickname('');
    }
  }, [open, defaultSection]);

  const formatDateTime = useCallback((value) => {
    if (!value) {
      return '—';
    }
    const timestamp = new Date(value);
    if (Number.isNaN(timestamp.getTime())) {
      return value;
    }
    return timestamp.toLocaleString();
  }, []);

  const handleRefresh = useCallback(() => {
    onRefresh?.();
  }, [onRefresh]);

  const handleCopyToken = useCallback(() => {
    if (!createdToken) {
      return;
    }
    if (navigator?.clipboard?.writeText) {
      navigator.clipboard.writeText(createdToken).catch(() => {});
    }
  }, [createdToken]);

  const handleDismissSecret = useCallback(() => {
    onDismissCreatedToken?.();
  }, [onDismissCreatedToken]);

  const handlePasskeyRefresh = useCallback(() => {
    onRefreshPasskeys?.();
  }, [onRefreshPasskeys]);

  const handlePasskeyRegister = useCallback(
    async (event) => {
      event.preventDefault();
      const nickname = newPasskeyNickname.trim();
      const result = await onRegisterPasskey?.({ nickname });
      if (result?.ok) {
        setNewPasskeyNickname('');
      }
    },
    [newPasskeyNickname, onRegisterPasskey],
  );

  const handlePasskeyRevoke = useCallback(
    async (passkey) => {
      if (!passkey?.id) {
        return;
      }
      const reasonInput = window.prompt('Optional reason for revoking this passkey:', '');
      const reason = reasonInput ? reasonInput.trim() : undefined;
      await onRevokePasskey?.(passkey.id, reason);
    },
    [onRevokePasskey],
  );

  const capabilitySetOptions = useMemo(
    () => capabilitySets.map((set) => ({
      value: set.id,
      label: set.label || set.slug || set.id,
      capabilities: Array.isArray(set.capabilities) ? set.capabilities : [],
    })),
    [capabilitySets],
  );

  const capabilitySetMap = useMemo(
    () => Object.fromEntries(capabilitySetOptions.map((option) => [option.value, option])),
    [capabilitySetOptions],
  );

  useEffect(() => {
    if (!capabilitySetOptions.length) {
      setNewTokenCapabilitySetId('');
      return;
    }
    if (!newTokenCapabilitySetId
      || !capabilitySetOptions.some((option) => option.value === newTokenCapabilitySetId)) {
      setNewTokenCapabilitySetId(capabilitySetOptions[0].value);
    }
  }, [capabilitySetOptions, newTokenCapabilitySetId]);

  const handleNewCapabilitySetChange = useCallback((event) => {
    setFormError(null);
    setNewTokenCapabilitySetId(event.target.value);
  }, []);

  const handleCreateToken = useCallback(
    async (event) => {
      event.preventDefault();
      setFormError(null);
      let normalizedLabel = newTokenLabel.trim();
      if (normalizedLabel.length === 0) {
        normalizedLabel = undefined;
      }

      let normalizedExpires;
      if (newTokenExpires) {
        const parsed = new Date(newTokenExpires);
        if (Number.isNaN(parsed.getTime())) {
          setFormError('Enter a valid expiration date.');
          return;
        }
        normalizedExpires = parsed.toISOString();
      }

      if (!capabilitySetOptions.length) {
        setFormError('Capability sets are still loading.');
        return;
      }

      const selectedCapabilitySetId = newTokenCapabilitySetId
        || capabilitySetOptions[0]?.value;
      if (!selectedCapabilitySetId) {
        setFormError('Select a capability set.');
        return;
      }

      const result = await onCreate?.({
        label: normalizedLabel,
        expires_at: normalizedExpires,
        capability_set_id: selectedCapabilitySetId,
      });

      if (result !== false) {
        setNewTokenLabel('');
        setNewTokenExpires('');
        setNewTokenCapabilitySetId(capabilitySetOptions[0]?.value || '');
        setFormError(null);
      }
    },
    [
      capabilitySetOptions,
      newTokenCapabilitySetId,
      newTokenExpires,
      newTokenLabel,
      onCreate,
    ],
  );

  const handleRegenerateToken = useCallback(
    async (token) => {
      if (!token?.id) {
        return;
      }
      await onRegenerate?.(token.id);
    },
    [onRegenerate],
  );

  const renderApiTokensSection = useMemo(() => {
    const hasTokens = Array.isArray(tokens) && tokens.length > 0;

    return (
      <div className="settings-section">
        <div className="settings-actions">
          <button
            type="button"
            className="secondary"
            onClick={handleRefresh}
            disabled={loading || capabilitySetsLoading}
          >
            {loading || capabilitySetsLoading ? 'Refreshing…' : 'Refresh'}
          </button>
        </div>

        <p>
          API tokens use predefined capability sets. Choose the set that matches the access you
          need when creating or updating a token.
        </p>

        {createdToken ? (
          <div className="settings-notice">
            <p>
              Copy this token now; you will not be able to view it again after closing this window.
            </p>
            <pre className="token-display">{createdToken}</pre>
            <div className="settings-notice__actions">
              <button type="button" className="secondary" onClick={handleCopyToken}>
                Copy token
              </button>
              <button type="button" onClick={handleDismissSecret}>
                Dismiss
              </button>
            </div>
          </div>
        ) : null}

        <form className="settings-form" onSubmit={handleCreateToken}>
          <div className="settings-form__field">
            <label htmlFor="api-token-label">Label</label>
            <input
              id="api-token-label"
              type="text"
              value={newTokenLabel}
              onChange={(event) => setNewTokenLabel(event.target.value)}
              placeholder="Personal API token"
            />
          </div>
          <div className="settings-form__field">
            <label htmlFor="api-token-expires">Expires at</label>
            <input
              id="api-token-expires"
              type="datetime-local"
              value={newTokenExpires}
              onChange={(event) => setNewTokenExpires(event.target.value)}
            />
          </div>
          <div className="settings-form__field">
            <label htmlFor="api-token-capability-set">Capability set</label>
            <select
              id="api-token-capability-set"
              value={newTokenCapabilitySetId}
              onChange={handleNewCapabilitySetChange}
              disabled={
                creating
                || capabilitySetsLoading
                || !capabilitySetOptions.length
              }
            >
              {!capabilitySetOptions.length ? (
                <option value="">No capability sets available</option>
              ) : null}
              {capabilitySetOptions.map((option) => (
                <option key={option.value} value={option.value}>
                  {option.label}
                </option>
              ))}
            </select>
            {capabilitySetsLoading ? (
              <small>Loading capability sets…</small>
            ) : null}
            {!capabilitySetsLoading && !capabilitySetOptions.length ? (
              <small>No capability sets available.</small>
            ) : null}
            {!capabilitySetsLoading
              && capabilitySetMap[newTokenCapabilitySetId]?.capabilities?.length ? (
                <small>
                  Includes: {capabilitySetMap[newTokenCapabilitySetId].capabilities.join(', ')}
                </small>
              ) : null}
          </div>
          <div className="settings-form__actions">
            <button
              type="submit"
              disabled={
                creating
                || capabilitySetsLoading
                || !capabilitySetOptions.length
              }
            >
              {creating ? 'Creating…' : 'Create token'}
            </button>
          </div>
        </form>
        {formError ? <p className="settings-form__error">{formError}</p> : null}

        {loading && !hasTokens ? (
          <p className="settings-empty">Loading tokens…</p>
        ) : null}

        {!loading && !hasTokens ? (
          <p className="settings-empty">No API tokens yet.</p>
        ) : null}

        {hasTokens ? (
          <table className="settings-table">
            <thead>
              <tr>
                <th scope="col">Label</th>
                <th scope="col">Created</th>
                <th scope="col">Last used</th>
                <th scope="col">Expires</th>
                <th scope="col">Capability set</th>
                <th scope="col">Actions</th>
              </tr>
            </thead>
            <tbody>
              {tokens.map((token) => {
                const isRevoked = Boolean(token?.revoked_at);
                const selectedSet = token?.capability_set_id
                  ? capabilitySetMap[token.capability_set_id]
                  : null;
                const capabilityList = Array.isArray(token?.capabilities) && token.capabilities.length
                  ? token.capabilities
                  : selectedSet?.capabilities || [];
                const capabilitySetLabel = selectedSet?.label
                  || selectedSet?.slug
                  || token.capability_set_id
                  || '—';
                return (
                  <tr key={token.id} className={isRevoked ? 'is-revoked' : undefined}>
                    <td>{token.label || '—'}</td>
                    <td>{formatDateTime(token.created_at)}</td>
                    <td>{formatDateTime(token.last_used_at)}</td>
                    <td>{formatDateTime(token.expires_at)}</td>
                    <td>
                      <div className="settings-capability-set">
                        <span className="settings-capability-set__label">{capabilitySetLabel}</span>
                      </div>
                      {capabilitySetsLoading ? (
                        <small>Loading capability sets…</small>
                      ) : null}
                      {!capabilitySetsLoading && capabilityList.length ? (
                        <div className="settings-capabilities">
                          <small>Includes: {capabilityList.join(', ')}</small>
                        </div>
                      ) : null}
                    </td>
                    <td className="settings-table__actions">
                      {isRevoked ? (
                        <span className="settings-status">Revoked</span>
                      ) : (
                        <>
                          <button
                            type="button"
                            className="secondary"
                            onClick={() => handleRegenerateToken(token)}
                            disabled={
                              regeneratingId === token.id || deletingId === token.id
                            }
                          >
                            {regeneratingId === token.id ? 'Regenerating…' : 'Regenerate'}
                          </button>
                          <button
                            type="button"
                            className="danger"
                            onClick={() => onDelete?.(token.id)}
                            disabled={
                              deletingId === token.id || regeneratingId === token.id
                            }
                          >
                            {deletingId === token.id ? 'Revoking…' : 'Revoke'}
                          </button>
                        </>
                      )}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        ) : null}
      </div>
    );
  }, [
    tokens,
    loading,
    createdToken,
    creating,
    deletingId,
    regeneratingId,
    newTokenLabel,
    newTokenExpires,
    newTokenCapabilitySetId,
    formError,
    capabilitySetOptions,
    capabilitySetMap,
    capabilitySetsLoading,
    formatDateTime,
    handleCopyToken,
    handleCreateToken,
    handleRegenerateToken,
    handleRefresh,
    onDelete,
    handleDismissSecret,
    handleNewCapabilitySetChange,
  ]);

  const renderPasskeysSection = useMemo(() => {
    const hasPasskeys = Array.isArray(passkeys) && passkeys.length > 0;

    return (
      <div className="settings-section">
        <div className="settings-actions">
          <button
            type="button"
            className="secondary"
            onClick={handlePasskeyRefresh}
            disabled={passkeysLoading}
          >
            {passkeysLoading ? 'Refreshing…' : 'Refresh'}
          </button>
        </div>

        {passkeysSupported === false ? (
          <p className="settings-empty">Passkeys are not enabled for this account.</p>
        ) : (
          <>
            <form className="settings-form" onSubmit={handlePasskeyRegister}>
              <div className="settings-form__field">
                <label htmlFor="passkey-nickname">Nickname (optional)</label>
                <input
                  id="passkey-nickname"
                  type="text"
                  placeholder="e.g. MacBook"
                  value={newPasskeyNickname}
                  onChange={(event) => setNewPasskeyNickname(event.target.value)}
                  disabled={registeringPasskey}
                />
              </div>
              <div className="settings-form__actions">
                <button type="submit" disabled={registeringPasskey}>
                  {registeringPasskey ? 'Registering…' : 'Register passkey'}
                </button>
              </div>
            </form>

            {passkeysLoading && !hasPasskeys ? (
              <p className="settings-empty">Loading passkeys…</p>
            ) : null}

            {!passkeysLoading && !hasPasskeys ? (
              <p className="settings-empty">No passkeys registered yet.</p>
            ) : null}

            {hasPasskeys ? (
              <table className="settings-table">
                <thead>
                  <tr>
                    <th scope="col">Nickname</th>
                    <th scope="col">Created</th>
                    <th scope="col">Last used</th>
                    <th scope="col">Transports</th>
                    <th scope="col">Status</th>
                    <th scope="col">Actions</th>
                  </tr>
                </thead>
                <tbody>
                  {passkeys.map((passkey) => {
                    const createdAt = passkey.created_at || passkey.createdAt;
                    const lastUsedAt = passkey.last_used_at || passkey.lastUsedAt;
                    const revokedAt = passkey.revoked_at || passkey.revokedAt;
                    const revokedReason = passkey.revoked_reason || passkey.revokedReason;
                    const revoked = Boolean(revokedAt);
                    const transports = Array.isArray(passkey.transports)
                      ? passkey.transports.filter(Boolean)
                      : [];

                    return (
                      <tr key={passkey.id} className={revoked ? 'is-revoked' : undefined}>
                        <td>{passkey.nickname || '—'}</td>
                        <td>{formatDateTime(createdAt)}</td>
                        <td>{formatDateTime(lastUsedAt)}</td>
                        <td>{transports.length ? transports.join(', ') : '—'}</td>
                        <td>
                          {revoked
                            ? revokedReason
                              ? `Revoked (${revokedReason})`
                              : 'Revoked'
                            : 'Active'}
                        </td>
                        <td className="settings-table__actions">
                          {revoked ? (
                            <span className="settings-status">Revoked</span>
                          ) : (
                            <button
                              type="button"
                              className="danger"
                              onClick={() => handlePasskeyRevoke(passkey)}
                              disabled={revokingPasskeyId === passkey.id}
                            >
                              {revokingPasskeyId === passkey.id ? 'Revoking…' : 'Revoke'}
                            </button>
                          )}
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            ) : null}
          </>
        )}
      </div>
    );
  }, [
    passkeys,
    passkeysLoading,
    passkeysSupported,
    registeringPasskey,
    revokingPasskeyId,
    newPasskeyNickname,
    formatDateTime,
    handlePasskeyRefresh,
    handlePasskeyRegister,
    handlePasskeyRevoke,
  ]);

  if (!open) {
    return null;
  }

  return (
    <div className="modal-backdrop" role="presentation" onClick={handleBackdropClick}>
      <div
        className="modal modal--panel settings-modal"
        role="dialog"
        aria-modal="true"
        aria-labelledby="settings-modal-title"
        onClick={handleInnerClick}
      >
        <PanelHeader
          className="panel-modal__header"
          title="Settings"
          titleTag="h3"
          titleProps={{ id: 'settings-modal-title' }}
          actions={(
            <button type="button" className="secondary" onClick={onClose}>
              Close
            </button>
          )}
        />
        <div className="settings-modal__body">
          <nav className="settings-modal__sidebar" aria-label="Settings sections">
            <ul>
              {SECTIONS.map((section) => (
                <li key={section.id}>
                  <button
                    type="button"
                    className={section.id === activeSection ? 'active' : ''}
                    onClick={() => setActiveSection(section.id)}
                  >
                    {section.label}
                  </button>
                </li>
              ))}
            </ul>
          </nav>
          <div className="settings-modal__content">
            {activeSection === 'passkeys' ? renderPasskeysSection : null}
            {activeSection === 'apiTokens' ? renderApiTokensSection : null}
            {activeSection !== 'passkeys' && activeSection !== 'apiTokens' ? (
              <p>Select a settings section.</p>
            ) : null}
          </div>
        </div>
      </div>
    </div>
  );
};

export default SettingsModal;
