import { LitElement, html, css, state, customElement, deesComms } from './plugins.js';
import type { CSSResult, TemplateResult } from './plugins.js';
import { sharedStyles, terminalStyles, navStyles } from './sw-dash-styles.js';
import type { IMetricsData } from './sw-dash-overview.js';
import type { ICachedResource } from './sw-dash-urls.js';
import type { IDomainStats } from './sw-dash-domains.js';
import type { IContentTypeStats } from './sw-dash-types.js';
import type { serviceworker } from '../ts_interfaces/index.js';

// Import components to register them
import './sw-dash-overview.js';
import './sw-dash-urls.js';
import './sw-dash-domains.js';
import './sw-dash-types.js';
import './sw-dash-events.js';
import './sw-dash-requests.js';
import './sw-dash-table.js';

type ViewType = 'overview' | 'urls' | 'domains' | 'types' | 'events' | 'requests';

interface IResourceData {
  resources: ICachedResource[];
  domains: IDomainStats[];
  contentTypes: IContentTypeStats[];
  resourceCount: number;
}

/**
 * Main SW Dashboard application shell
 *
 * Architecture:
 * - ONE initial HTTP seed request to /sw-dash/metrics (provides ALL data)
 * - HTTP heartbeat every 30s for SW health check
 * - Everything else via DeesComms (push from SW, requests to SW)
 */
@customElement('sw-dash-app')
export class SwDashApp extends LitElement {
  public static styles: CSSResult[] = [
    sharedStyles,
    terminalStyles,
    navStyles,
    css`
      :host {
        display: block;
        background: var(--bg-primary);
        min-height: 100vh;
        padding: var(--space-5);
      }

      .view {
        display: none;
      }

      .view.active {
        display: block;
      }

      .header-left {
        display: flex;
        align-items: center;
        gap: var(--space-3);
      }

      .logo {
        width: 24px;
        height: 24px;
        background: var(--accent-primary);
        border-radius: var(--radius-sm);
        display: flex;
        align-items: center;
        justify-content: center;
        font-weight: 700;
        font-size: 12px;
        color: white;
      }

      .uptime-badge {
        display: inline-flex;
        align-items: center;
        gap: var(--space-1);
        padding: var(--space-1) var(--space-2);
        background: var(--bg-tertiary);
        border-radius: var(--radius-sm);
        font-size: 11px;
        color: var(--text-tertiary);
      }

      .uptime-badge .value {
        color: var(--text-primary);
        font-weight: 500;
        font-variant-numeric: tabular-nums;
      }

      .footer-left {
        display: flex;
        align-items: center;
        gap: var(--space-2);
        color: var(--text-tertiary);
        font-size: 11px;
      }

      .footer-right {
        display: flex;
        align-items: center;
        gap: var(--space-2);
      }

      .auto-refresh {
        display: inline-flex;
        align-items: center;
        gap: var(--space-1);
        padding: var(--space-1) var(--space-2);
        background: rgba(34, 197, 94, 0.1);
        color: var(--accent-success);
        border-radius: var(--radius-sm);
        font-size: 11px;
        font-weight: 500;
      }

      .auto-refresh .dot {
        width: 5px;
        height: 5px;
        border-radius: 50%;
        background: currentColor;
        animation: pulse 2s infinite;
      }

      @keyframes pulse {
        0%, 100% { opacity: 1; }
        50% { opacity: 0.4; }
      }
    `
  ];

  // Core metrics
  @state() accessor currentView: ViewType = 'overview';
  @state() accessor metrics: IMetricsData | null = null;
  @state() accessor lastRefresh = new Date().toLocaleTimeString();
  @state() accessor isConnected = false;

  // Resource data (from initial seed)
  @state() accessor resourceData: IResourceData = {
    resources: [],
    domains: [],
    contentTypes: [],
    resourceCount: 0
  };

  // Events data (from initial seed + push updates)
  @state() accessor events: serviceworker.IEventLogEntry[] = [];
  @state() accessor eventTotalCount = 0;
  @state() accessor eventCountLastHour = 0;

  // Request logs data (from initial seed + push updates)
  @state() accessor requestLogs: serviceworker.ITypedRequestLogEntry[] = [];
  @state() accessor requestTotalCount = 0;
  @state() accessor requestStats: serviceworker.ITypedRequestStats | null = null;
  @state() accessor requestMethods: string[] = [];

  // DeesComms for communication with service worker
  private comms: deesComms.DeesComms | null = null;

  // Heartbeat interval (30 seconds) for SW health check
  private heartbeatInterval: ReturnType<typeof setInterval> | null = null;
  private readonly HEARTBEAT_INTERVAL_MS = 30000;

  connectedCallback(): void {
    super.connectedCallback();
    // Initial HTTP seed request to wake up SW and get ALL initial data
    this.loadInitialData();
    // Setup push listeners via DeesComms
    this.setupPushListeners();
    // Start heartbeat for SW health check
    this.startHeartbeat();
  }

  disconnectedCallback(): void {
    super.disconnectedCallback();
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
    }
  }

  /**
   * Initial HTTP request to seed ALL data and wake up service worker
   * This is the ONE HTTP request that provides everything:
   * - Core metrics
   * - Resources, domains, content types
   * - Events (initial 50)
   * - Request logs (initial 50), stats, methods
   */
  private async loadInitialData(): Promise<void> {
    try {
      const response = await fetch('/sw-dash/metrics');
      const data = await response.json();

      // Core metrics
      this.metrics = data;

      // Resource data
      this.resourceData = {
        resources: data.resources || [],
        domains: data.domains || [],
        contentTypes: data.contentTypes || [],
        resourceCount: data.resourceCount || 0,
      };

      // Events data
      this.events = data.events || [];
      this.eventTotalCount = data.eventTotalCount || 0;
      this.eventCountLastHour = data.eventCountLastHour || 0;

      // Request logs data
      this.requestLogs = data.requestLogs || [];
      this.requestTotalCount = data.requestTotalCount || 0;
      this.requestStats = data.requestStats || null;
      this.requestMethods = data.requestMethods || [];

      this.lastRefresh = new Date().toLocaleTimeString();
      this.isConnected = true;
    } catch (err) {
      console.error('Failed to load initial data:', err);
      this.isConnected = false;
    }
  }

  /**
   * Setup DeesComms handlers for receiving push updates from SW
   * All real-time updates come through here
   */
  private setupPushListeners(): void {
    this.comms = new deesComms.DeesComms();

    // Handle metrics push updates
    this.comms.createTypedHandler<serviceworker.IMessage_Serviceworker_MetricsUpdate>(
      'serviceworker_metricsUpdate',
      async (snapshot) => {
        // Update metrics from push
        if (this.metrics) {
          this.metrics = {
            ...this.metrics,
            cache: {
              ...this.metrics.cache,
              hits: snapshot.cache.hits,
              misses: snapshot.cache.misses,
              errors: snapshot.cache.errors,
              bytesServedFromCache: snapshot.cache.bytesServedFromCache,
              bytesFetched: snapshot.cache.bytesFetched,
            },
            network: {
              ...this.metrics.network,
              totalRequests: snapshot.network.totalRequests,
              successfulRequests: snapshot.network.successfulRequests,
              failedRequests: snapshot.network.failedRequests,
            },
            cacheHitRate: snapshot.cacheHitRate,
            networkSuccessRate: snapshot.networkSuccessRate,
            resourceCount: snapshot.resourceCount,
            uptime: snapshot.uptime,
          };
        }
        this.lastRefresh = new Date().toLocaleTimeString();
        this.isConnected = true;
        return {};
      }
    );

    // Handle new event logged - add to our events array
    this.comms.createTypedHandler<serviceworker.IMessage_Serviceworker_EventLogged>(
      'serviceworker_eventLogged',
      async (entry) => {
        // Prepend new event to array
        this.events = [entry, ...this.events];
        this.eventTotalCount++;
        // Check if event is within last hour
        const oneHourAgo = Date.now() - 3600000;
        if (entry.timestamp >= oneHourAgo) {
          this.eventCountLastHour++;
        }
        return {};
      }
    );

    // Handle resource cached push updates
    this.comms.createTypedHandler<serviceworker.IMessage_Serviceworker_ResourceCached>(
      'serviceworker_resourceCached',
      async (resource) => {
        // Update resource count optimistically
        if (resource.cached && this.metrics) {
          this.metrics = {
            ...this.metrics,
            resourceCount: this.metrics.resourceCount + 1,
          };
        }
        return {};
      }
    );

    // Handle new TypedRequest logged - add to our logs array
    this.comms.createTypedHandler<serviceworker.IMessage_Serviceworker_TypedRequestLogged>(
      'serviceworker_typedRequestLogged',
      async (entry) => {
        // Prepend new log to array
        this.requestLogs = [entry, ...this.requestLogs];
        this.requestTotalCount++;

        // Update stats optimistically
        if (this.requestStats) {
          const newStats = { ...this.requestStats };
          if (entry.phase === 'request') {
            newStats.totalRequests++;
          } else {
            newStats.totalResponses++;
          }
          if (entry.error) {
            newStats.errorCount++;
          }
          // Update method counts
          if (!newStats.methodCounts[entry.method]) {
            newStats.methodCounts[entry.method] = { requests: 0, responses: 0, errors: 0, avgDurationMs: 0 };
            // Add to methods list if new
            if (!this.requestMethods.includes(entry.method)) {
              this.requestMethods = [...this.requestMethods, entry.method];
            }
          }
          if (entry.phase === 'request') {
            newStats.methodCounts[entry.method].requests++;
          } else {
            newStats.methodCounts[entry.method].responses++;
          }
          if (entry.error) {
            newStats.methodCounts[entry.method].errors++;
          }
          this.requestStats = newStats;
        }
        return {};
      }
    );
  }

  /**
   * Heartbeat to check SW health periodically (HTTP)
   * This is the ONLY periodic HTTP request
   */
  private startHeartbeat(): void {
    this.heartbeatInterval = setInterval(async () => {
      try {
        const response = await fetch('/sw-dash/metrics');
        if (response.ok) {
          this.isConnected = true;
          // Refresh all data from heartbeat response
          const data = await response.json();
          this.metrics = data;
          this.resourceData = {
            resources: data.resources || [],
            domains: data.domains || [],
            contentTypes: data.contentTypes || [],
            resourceCount: data.resourceCount || 0,
          };
          this.events = data.events || [];
          this.eventTotalCount = data.eventTotalCount || 0;
          this.eventCountLastHour = data.eventCountLastHour || 0;
          this.requestLogs = data.requestLogs || [];
          this.requestTotalCount = data.requestTotalCount || 0;
          this.requestStats = data.requestStats || null;
          this.requestMethods = data.requestMethods || [];
          this.lastRefresh = new Date().toLocaleTimeString();
        } else {
          this.isConnected = false;
        }
      } catch {
        this.isConnected = false;
      }
    }, this.HEARTBEAT_INTERVAL_MS);
  }

  /**
   * Handle "load more events" request from sw-dash-events component
   * Uses DeesComms to request older events from SW
   */
  private async handleLoadMoreEvents(e: CustomEvent<{ before: number }>): Promise<void> {
    if (!this.comms) return;

    try {
      const tr = this.comms.createTypedRequest<serviceworker.IRequest_Serviceworker_GetEventLog>('serviceworker_getEventLog');
      const result = await tr.fire({
        limit: 50,
        before: e.detail.before,
      });
      // Append older events to existing array
      this.events = [...this.events, ...result.events];
      this.eventTotalCount = result.totalCount;
    } catch (err) {
      console.error('Failed to load more events:', err);
    }
  }

  /**
   * Handle "clear events" request from sw-dash-events component
   * Uses DeesComms to clear event log in SW
   */
  private async handleClearEvents(): Promise<void> {
    if (!this.comms) return;

    try {
      const tr = this.comms.createTypedRequest<serviceworker.IRequest_Serviceworker_ClearEventLog>('serviceworker_clearEventLog');
      await tr.fire({});
      // Clear local state
      this.events = [];
      this.eventTotalCount = 0;
      this.eventCountLastHour = 0;
    } catch (err) {
      console.error('Failed to clear events:', err);
    }
  }

  /**
   * Handle "load more requests" from sw-dash-requests component
   * Uses DeesComms to request older request logs from SW
   */
  private async handleLoadMoreRequests(e: CustomEvent<{ before: number; method?: string }>): Promise<void> {
    if (!this.comms) return;

    try {
      const tr = this.comms.createTypedRequest<serviceworker.IRequest_Serviceworker_GetTypedRequestLogs>('serviceworker_getTypedRequestLogs');
      const result = await tr.fire({
        limit: 50,
        before: e.detail.before,
        method: e.detail.method,
      });
      // Append older logs to existing array
      this.requestLogs = [...this.requestLogs, ...result.logs];
      this.requestTotalCount = result.totalCount;
    } catch (err) {
      console.error('Failed to load more requests:', err);
    }
  }

  /**
   * Handle "clear requests" from sw-dash-requests component
   * Uses DeesComms to clear request logs in SW
   */
  private async handleClearRequests(): Promise<void> {
    if (!this.comms) return;

    try {
      const tr = this.comms.createTypedRequest<serviceworker.IRequest_Serviceworker_ClearTypedRequestLogs>('serviceworker_clearTypedRequestLogs');
      await tr.fire({});
      // Clear local state
      this.requestLogs = [];
      this.requestTotalCount = 0;
      this.requestStats = {
        totalRequests: 0,
        totalResponses: 0,
        methodCounts: {},
        errorCount: 0,
        avgDurationMs: 0,
      };
      this.requestMethods = [];
    } catch (err) {
      console.error('Failed to clear requests:', err);
    }
  }

  private setView(view: ViewType): void {
    this.currentView = view;
    // No HTTP fetch on view change - data is already loaded from initial seed
  }

  private handleSpeedtestComplete(_e: CustomEvent): void {
    // Refresh metrics after speedtest via HTTP
    this.loadInitialData();
  }

  private formatUptime(ms: number): string {
    const s = Math.floor(ms / 1000);
    const m = Math.floor(s / 60);
    const h = Math.floor(m / 60);
    const d = Math.floor(h / 24);
    if (d > 0) return `${d}d ${h % 24}h`;
    if (h > 0) return `${h}h ${m % 60}m`;
    if (m > 0) return `${m}m ${s % 60}s`;
    return `${s}s`;
  }

  public render(): TemplateResult {
    return html`
      <div class="terminal">
        <div class="header">
          <div class="header-left">
            <div class="logo">SW</div>
            <span class="title">Service Worker Dashboard</span>
          </div>
          <div class="uptime-badge">
            Uptime: <span class="value">${this.metrics ? this.formatUptime(this.metrics.uptime) : '--'}</span>
          </div>
        </div>

        <nav class="nav">
          <button
            class="nav-tab ${this.currentView === 'overview' ? 'active' : ''}"
            @click="${() => this.setView('overview')}"
          >Overview</button>
          <button
            class="nav-tab ${this.currentView === 'urls' ? 'active' : ''}"
            @click="${() => this.setView('urls')}"
          >URLs <span class="count">${this.resourceData.resourceCount}</span></button>
          <button
            class="nav-tab ${this.currentView === 'domains' ? 'active' : ''}"
            @click="${() => this.setView('domains')}"
          >Domains</button>
          <button
            class="nav-tab ${this.currentView === 'types' ? 'active' : ''}"
            @click="${() => this.setView('types')}"
          >Types</button>
          <button
            class="nav-tab ${this.currentView === 'events' ? 'active' : ''}"
            @click="${() => this.setView('events')}"
          >Events</button>
          <button
            class="nav-tab ${this.currentView === 'requests' ? 'active' : ''}"
            @click="${() => this.setView('requests')}"
          >Requests</button>
        </nav>

        <div class="content">
          <div class="view ${this.currentView === 'overview' ? 'active' : ''}">
            <sw-dash-overview
              .metrics="${this.metrics}"
              .eventCountLastHour="${this.eventCountLastHour}"
              @speedtest-complete="${this.handleSpeedtestComplete}"
            ></sw-dash-overview>
          </div>

          <div class="view ${this.currentView === 'urls' ? 'active' : ''}">
            <sw-dash-urls .resources="${this.resourceData.resources}"></sw-dash-urls>
          </div>

          <div class="view ${this.currentView === 'domains' ? 'active' : ''}">
            <sw-dash-domains .domains="${this.resourceData.domains}"></sw-dash-domains>
          </div>

          <div class="view ${this.currentView === 'types' ? 'active' : ''}">
            <sw-dash-types .contentTypes="${this.resourceData.contentTypes}"></sw-dash-types>
          </div>

          <div class="view ${this.currentView === 'events' ? 'active' : ''}">
            <sw-dash-events
              .events="${this.events}"
              .totalCount="${this.eventTotalCount}"
              @load-more-events="${this.handleLoadMoreEvents}"
              @clear-events="${this.handleClearEvents}"
            ></sw-dash-events>
          </div>

          <div class="view ${this.currentView === 'requests' ? 'active' : ''}">
            <sw-dash-requests
              .logs="${this.requestLogs}"
              .totalCount="${this.requestTotalCount}"
              .stats="${this.requestStats}"
              .methods="${this.requestMethods}"
              @load-more-requests="${this.handleLoadMoreRequests}"
              @clear-requests="${this.handleClearRequests}"
            ></sw-dash-requests>
          </div>
        </div>

        <div class="footer">
          <div class="footer-left">
            Last updated: ${this.lastRefresh}
          </div>
          <div class="footer-right">
            <div class="auto-refresh">
              <span class="dot"></span>
              Live
            </div>
          </div>
        </div>
      </div>
    `;
  }
}
