/**
 * EncryptID Login Button Component
 *
 * A customizable login button that handles WebAuthn authentication
 * and key derivation. Can be embedded in any r-ecosystem app.
 */

import {
  registerPasskey,
  authenticatePasskey,
  detectCapabilities,
  startConditionalUI,
  WebAuthnCapabilities,
} from '../webauthn';
import { getKeyManager } from '../key-derivation';
import { getSessionManager, AuthLevel } from '../session';
import { getDocBridge, resetDocBridge } from '../../../shared/local-first/encryptid-bridge';
import { getVaultManager, resetVaultManager } from '../vault';

// ============================================================================
// STYLES
// ============================================================================

const styles = `
  :host {
    --eid-primary: #06b6d4;
    --eid-primary-hover: #0891b2;
    --eid-bg: #0f172a;
    --eid-bg-hover: #1e293b;
    --eid-text: #f1f5f9;
    --eid-text-secondary: #94a3b8;
    --eid-radius: 8px;
    --eid-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.3);

    display: inline-block;
    font-family: system-ui, -apple-system, sans-serif;
  }

  .login-container {
    position: relative;
  }

  .login-btn {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 24px;
    background: var(--eid-primary);
    color: white;
    border: none;
    border-radius: var(--eid-radius);
    font-size: 1rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s;
    box-shadow: var(--eid-shadow);
  }

  .login-btn:hover {
    background: var(--eid-primary-hover);
    transform: translateY(-1px);
  }

  .login-btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
    transform: none;
  }

  .login-btn.outline {
    background: transparent;
    border: 2px solid var(--eid-primary);
    color: var(--eid-primary);
  }

  .login-btn.outline:hover {
    background: var(--eid-primary);
    color: white;
  }

  .login-btn.small {
    padding: 8px 16px;
    font-size: 0.875rem;
  }

  .login-btn.large {
    padding: 16px 32px;
    font-size: 1.125rem;
  }

  .passkey-icon {
    width: 24px;
    height: 24px;
  }

  .login-btn.small .passkey-icon {
    width: 18px;
    height: 18px;
  }

  .login-btn.large .passkey-icon {
    width: 28px;
    height: 28px;
  }

  .user-info {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 16px;
    background: var(--eid-bg);
    border-radius: var(--eid-radius);
    color: var(--eid-text);
  }

  .user-avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--eid-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: 0.875rem;
  }

  .user-details {
    flex: 1;
    min-width: 0;
  }

  .user-did {
    font-size: 0.75rem;
    color: var(--eid-text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 150px;
  }

  .auth-level {
    font-size: 0.625rem;
    padding: 2px 6px;
    border-radius: 4px;
    background: var(--eid-bg-hover);
  }

  .auth-level.elevated {
    background: rgba(34, 197, 94, 0.2);
    color: #22c55e;
  }

  .auth-level.standard {
    background: rgba(234, 179, 8, 0.2);
    color: #eab308;
  }

  .logout-btn {
    padding: 6px 12px;
    background: transparent;
    border: 1px solid var(--eid-text-secondary);
    border-radius: var(--eid-radius);
    color: var(--eid-text-secondary);
    font-size: 0.75rem;
    cursor: pointer;
    transition: all 0.2s;
  }

  .logout-btn:hover {
    border-color: #ef4444;
    color: #ef4444;
  }

  .dropdown {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 8px;
    background: var(--eid-bg);
    border-radius: var(--eid-radius);
    box-shadow: var(--eid-shadow);
    min-width: 200px;
    z-index: 100;
    overflow: hidden;
  }

  .dropdown-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    color: var(--eid-text);
    text-decoration: none;
    cursor: pointer;
    transition: background 0.2s;
  }

  .dropdown-item:hover {
    background: var(--eid-bg-hover);
  }

  .dropdown-item.danger {
    color: #ef4444;
  }

  .dropdown-divider {
    height: 1px;
    background: #334155;
    margin: 4px 0;
  }

  .loading-spinner {
    width: 20px;
    height: 20px;
    border: 2px solid transparent;
    border-top-color: currentColor;
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
  }

  @keyframes spin {
    to { transform: rotate(360deg); }
  }

  .hidden {
    display: none;
  }
`;

// ============================================================================
// PASSKEY SVG ICON
// ============================================================================

const PASSKEY_ICON = `
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="passkey-icon">
  <circle cx="12" cy="10" r="3"/>
  <path d="M12 13v8"/>
  <path d="M9 18h6"/>
  <circle cx="12" cy="10" r="7"/>
</svg>
`;

// ============================================================================
// WEB COMPONENT
// ============================================================================

export class EncryptIDLoginButton extends HTMLElement {
  private shadow: ShadowRoot;
  private loading: boolean = false;
  private showDropdown: boolean = false;
  private capabilities: WebAuthnCapabilities | null = null;

  // Configurable attributes
  static get observedAttributes() {
    return ['size', 'variant', 'label', 'show-user'];
  }

  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: 'open' });
  }

  async connectedCallback() {
    // Detect capabilities
    this.capabilities = await detectCapabilities();

    // Start conditional UI if available
    if (this.capabilities.conditionalUI) {
      this.startConditionalAuth();
    }

    this.render();

    // Close dropdown on outside click
    document.addEventListener('click', (e) => {
      if (!this.contains(e.target as Node)) {
        this.showDropdown = false;
        this.render();
      }
    });
  }

  attributeChangedCallback() {
    this.render();
  }

  private get size(): 'small' | 'medium' | 'large' {
    return (this.getAttribute('size') as any) || 'medium';
  }

  private get variant(): 'primary' | 'outline' {
    return (this.getAttribute('variant') as any) || 'primary';
  }

  private get label(): string {
    return this.getAttribute('label') || 'Sign in with Passkey';
  }

  private get showUser(): boolean {
    return this.hasAttribute('show-user');
  }

  private render() {
    const session = getSessionManager();
    const isLoggedIn = session.isValid();
    const did = session.getDID();
    const authLevel = session.getAuthLevel();

    this.shadow.innerHTML = `
      <style>${styles}</style>
      <div class="login-container">
        ${isLoggedIn && this.showUser ? this.renderUserInfo(did!, authLevel) : this.renderLoginButton()}
        ${this.showDropdown ? this.renderDropdown() : ''}
      </div>
    `;

    this.attachEventListeners();
  }

  private renderLoginButton(): string {
    const sizeClass = this.size === 'medium' ? '' : this.size;
    const variantClass = this.variant === 'primary' ? '' : this.variant;

    return `
      <button class="login-btn ${sizeClass} ${variantClass}" ${this.loading ? 'disabled' : ''}>
        ${this.loading
          ? '<div class="loading-spinner"></div>'
          : PASSKEY_ICON
        }
        <span>${this.loading ? 'Authenticating...' : this.label}</span>
      </button>
    `;
  }

  private renderUserInfo(did: string, authLevel: AuthLevel): string {
    const shortDID = did.slice(0, 20) + '...' + did.slice(-8);
    const initial = did.slice(8, 10).toUpperCase();
    const levelName = AuthLevel[authLevel].toLowerCase();

    return `
      <div class="user-info" style="cursor: pointer;">
        <div class="user-avatar">${initial}</div>
        <div class="user-details">
          <div class="user-did">${shortDID}</div>
          <span class="auth-level ${levelName}">${levelName}</span>
        </div>
      </div>
    `;
  }

  private renderDropdown(): string {
    return `
      <div class="dropdown">
        <div class="dropdown-item" data-action="profile">
          👤 Profile
        </div>
        <div class="dropdown-item" data-action="recovery">
          🛡️ Recovery Settings
        </div>
        <div class="dropdown-item" data-action="upgrade">
          🔐 Upgrade Auth Level
        </div>
        <div class="dropdown-divider"></div>
        <div class="dropdown-item danger" data-action="logout">
          🚪 Sign Out
        </div>
      </div>
    `;
  }

  private attachEventListeners() {
    const session = getSessionManager();
    const isLoggedIn = session.isValid();

    if (isLoggedIn && this.showUser) {
      // User info click - toggle dropdown
      this.shadow.querySelector('.user-info')?.addEventListener('click', () => {
        this.showDropdown = !this.showDropdown;
        this.render();
      });

      // Dropdown actions
      this.shadow.querySelectorAll('.dropdown-item').forEach(item => {
        item.addEventListener('click', (e) => {
          e.stopPropagation();
          const action = (item as HTMLElement).dataset.action;
          this.handleDropdownAction(action!);
        });
      });
    } else {
      // Login button click
      this.shadow.querySelector('.login-btn')?.addEventListener('click', () => {
        this.handleLogin();
      });
    }
  }

  private async handleLogin() {
    if (this.loading) return;

    this.loading = true;
    this.render();

    try {
      // Try to authenticate with existing passkey
      const result = await authenticatePasskey();

      // Initialize key manager with PRF output
      const keyManager = getKeyManager();
      if (result.prfOutput) {
        await keyManager.initFromPRF(result.prfOutput);
        // Initialize doc encryption bridge for local-first encrypted storage
        await getDocBridge().initFromAuth(result.prfOutput);
        // Load encrypted account vault in background
        const docCrypto = getDocBridge().getDocCrypto();
        if (docCrypto) {
          getVaultManager(docCrypto).load().catch(err =>
            console.warn('Vault load failed:', err)
          );
        }
      }

      // Get derived keys
      const keys = await keyManager.getKeys();

      // Create session
      const sessionManager = getSessionManager();
      await sessionManager.createSession(result, keys.did, {
        encrypt: true,
        sign: true,
        wallet: false,  // Will be true after wallet setup
      });

      // Dispatch success event
      this.dispatchEvent(new CustomEvent('login-success', {
        detail: {
          did: keys.did,
          credentialId: result.credentialId,
          prfAvailable: !!result.prfOutput,
        },
        bubbles: true,
      }));

    } catch (error: any) {
      // If no credential found, offer to register
      if (error.name === 'NotAllowedError' || error.message?.includes('No credential')) {
        this.dispatchEvent(new CustomEvent('login-register-needed', {
          bubbles: true,
        }));
      } else {
        this.dispatchEvent(new CustomEvent('login-error', {
          detail: { error: error.message },
          bubbles: true,
        }));
      }
    } finally {
      this.loading = false;
      this.render();
    }
  }

  private async handleDropdownAction(action: string) {
    this.showDropdown = false;

    switch (action) {
      case 'profile':
        this.dispatchEvent(new CustomEvent('navigate', {
          detail: { path: '/profile' },
          bubbles: true,
        }));
        break;

      case 'recovery':
        this.dispatchEvent(new CustomEvent('navigate', {
          detail: { path: '/recovery' },
          bubbles: true,
        }));
        break;

      case 'upgrade':
        await this.handleUpgradeAuth();
        break;

      case 'logout':
        this.handleLogout();
        break;
    }

    this.render();
  }

  private async handleUpgradeAuth() {
    try {
      const result = await authenticatePasskey();

      const sessionManager = getSessionManager();
      sessionManager.upgradeAuthLevel(AuthLevel.ELEVATED);

      this.dispatchEvent(new CustomEvent('auth-upgraded', {
        detail: { level: AuthLevel.ELEVATED },
        bubbles: true,
      }));
    } catch (error) {
      console.error('Failed to upgrade auth:', error);
    }
  }

  private handleLogout() {
    const sessionManager = getSessionManager();
    sessionManager.clearSession();

    const keyManager = getKeyManager();
    keyManager.clear();

    // Clear vault and doc encryption bridge key material
    resetVaultManager();
    resetDocBridge();

    this.dispatchEvent(new CustomEvent('logout', { bubbles: true }));
    this.render();
  }

  private async startConditionalAuth() {
    // Start listening for conditional UI (passkey autofill)
    try {
      const result = await startConditionalUI();
      if (result) {
        // User selected a passkey from autofill
        const keyManager = getKeyManager();
        if (result.prfOutput) {
          await keyManager.initFromPRF(result.prfOutput);
          await getDocBridge().initFromAuth(result.prfOutput);
          // Load encrypted account vault in background
          const docCrypto = getDocBridge().getDocCrypto();
          if (docCrypto) {
            getVaultManager(docCrypto).load().catch(err =>
              console.warn('Vault load failed:', err)
            );
          }
        }

        const keys = await keyManager.getKeys();

        const sessionManager = getSessionManager();
        await sessionManager.createSession(result, keys.did, {
          encrypt: true,
          sign: true,
          wallet: false,
        });

        this.dispatchEvent(new CustomEvent('login-success', {
          detail: {
            did: keys.did,
            credentialId: result.credentialId,
            prfAvailable: !!result.prfOutput,
            viaConditionalUI: true,
          },
          bubbles: true,
        }));

        this.render();
      }
    } catch (error) {
      // Conditional UI cancelled or not available
      console.log('Conditional UI not completed:', error);
    }
  }

  /**
   * Public method to trigger registration flow
   */
  async register(username: string, displayName: string): Promise<void> {
    this.loading = true;
    this.render();

    try {
      const credential = await registerPasskey(username, displayName);

      this.dispatchEvent(new CustomEvent('register-success', {
        detail: {
          credentialId: credential.credentialId,
          prfSupported: credential.prfSupported,
        },
        bubbles: true,
      }));

      // Auto-login after registration
      await this.handleLogin();
    } catch (error: any) {
      this.dispatchEvent(new CustomEvent('register-error', {
        detail: { error: error.message },
        bubbles: true,
      }));
    } finally {
      this.loading = false;
      this.render();
    }
  }
}

// Register the custom element
customElements.define('encryptid-login', EncryptIDLoginButton);
