import * as plugins from '../plugins.js';
import * as shared from './shared/index.js';
import * as appstate from '../appstate.js';
import { appRouter } from '../router.js';
import {
  DeesElement,
  customElement,
  html,
  state,
  css,
  cssManager,
  type TemplateResult,
} from '@design.estate/dees-element';

const byteUnits = ['B', 'KB', 'MB', 'GB', 'TB'];

function getByteUnitIndex(bytes: number): number {
  if (!bytes || bytes === 0) return 0;
  return Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), byteUnits.length - 1);
}

function formatBytes(bytes: number, forcedUnitIndex?: number): string {
  if ((!bytes || bytes === 0) && forcedUnitIndex === undefined) return '0 B';
  const unitIndex = forcedUnitIndex ?? getByteUnitIndex(bytes);
  const value = bytes / Math.pow(1024, unitIndex);
  return `${value.toFixed(1)} ${byteUnits[unitIndex]}`;
}

@customElement('ob-view-dashboard')
export class ObViewDashboard extends DeesElement {
  @state()
  accessor systemState: appstate.ISystemState = {
    status: null,
    resource: { phase: 'idle', error: null, lastSuccessAt: null },
  };

  @state()
  accessor servicesState: appstate.IServicesState = {
    services: [],
    currentService: null,
    currentHostedAppLifecycle: null,
    currentServiceLogs: [],
    currentServiceStats: null,
    platformServices: [],
    currentPlatformService: null,
    currentPlatformServiceStats: null,
    currentPlatformServiceLogs: [],
  };

  @state()
  accessor networkState: appstate.INetworkState = {
    targets: [],
    stats: null,
    statsResource: { phase: 'idle', error: null, lastSuccessAt: null },
    trafficStats: null,
    dnsRecords: [],
    domains: [],
    gatewayDomains: [],
    gatewayDnsRecords: [],
    certificates: [],
  };

  constructor() {
    super();

    const systemSub = appstate.systemStatePart
      .select((s) => s)
      .subscribe((newState) => {
        this.systemState = newState;
      });
    this.rxSubscriptions.push(systemSub);

    const servicesSub = appstate.servicesStatePart
      .select((s) => s)
      .subscribe((newState) => {
        this.servicesState = newState;
      });
    this.rxSubscriptions.push(servicesSub);

    const networkSub = appstate.networkStatePart
      .select((s) => s)
      .subscribe((newState) => {
        this.networkState = newState;
      });
    this.rxSubscriptions.push(networkSub);
  }

  public static styles = [
    cssManager.defaultStyles,
    shared.viewHostCss,
    css`
      .dashboard {
        display: flex;
        flex-direction: column;
        gap: 24px;
      }

      .section {
        display: flex;
        flex-direction: column;
      }

      .section-title {
        font-size: 18px;
        font-weight: 600;
        color: ${cssManager.bdTheme('#18181b', '#fafafa')};
        margin: 0 0 12px;
      }

      .services-grid {
        display: grid;
        grid-template-columns: 1fr;
        gap: 16px;
        align-items: stretch;
      }

      .services-grid > * {
        height: 100%;
      }


      .status-panel {
        padding: 18px;
        border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#3f3f46')};
        border-radius: 10px;
        color: ${cssManager.bdTheme('#52525b', '#a1a1aa')};
        background: ${cssManager.bdTheme('#fafafa', '#18181b')};
      }

      .status-panel button {
        margin-left: 12px;
        padding: 6px 10px;
        border: 0;
        border-radius: 6px;
        cursor: pointer;
      }

      .stale-warning {
        margin-bottom: 10px;
        padding: 8px 10px;
        border-radius: 8px;
        color: ${cssManager.bdTheme('#92400e', '#fbbf24')};
        background: ${cssManager.bdTheme('#fffbeb', '#422006')};
      }
      @media (min-width: 768px) {
        .services-grid {
          grid-template-columns: 1fr 1fr;
        }
      }
    `,
  ];

  async connectedCallback() {
    super.connectedCallback();
    await Promise.allSettled([
      appstate.fetchSystemStatus(),
      appstate.dispatchProtectedAction(appstate.fetchServicesAction, null),
      appstate.dispatchProtectedAction(appstate.fetchPlatformServicesAction, null),
      appstate.fetchNetworkStats(),
      appstate.dispatchProtectedAction(appstate.fetchTrafficStatsAction, null),
      appstate.dispatchProtectedAction(appstate.fetchCertificatesAction, null),
    ]);
  }

  public render(): TemplateResult {
    const status = this.systemState.status;
    const services = this.servicesState.services;
    const platformServices = this.servicesState.platformServices;
    const networkStats = this.networkState.stats;
    const trafficStats = this.networkState.trafficStats;
    const certificates = this.networkState.certificates;
    const statusCounts = trafficStats?.statusCounts || {};

    const runningServices = services.filter((s) => s.status === 'running').length;
    const stoppedServices = services.filter((s) => s.status === 'stopped').length;
    const memoryUnitIndex = getByteUnitIndex(
      status?.docker?.memoryTotal || status?.docker?.memoryUsage || 0,
    );

    const validCerts = certificates.filter((c) => c.isValid).length;
    const expiringCerts = certificates.filter(
      (c) => c.isValid && c.expiryDate && c.expiryDate - Date.now() < 30 * 24 * 60 * 60 * 1000,
    ).length;
    const expiredCerts = certificates.filter((c) => !c.isValid).length;

    const dashboardData = {
      cluster: status ? {
        totalServices: services.length,
        running: runningServices,
        stopped: stoppedServices,
        dockerStatus: status.docker.running ? 'running' as const : 'stopped' as const,
      } : null,
      resourceUsage: status ? {
        cpu: status.docker.cpuUsage,
        memoryUsed: formatBytes(status.docker.memoryUsage, memoryUnitIndex),
        memoryTotal: formatBytes(status.docker.memoryTotal, memoryUnitIndex),
        networkIn: formatBytes(status.docker.networkIn),
        networkOut: formatBytes(status.docker.networkOut),
        topConsumers: [],
      } : null,
      platformServices: platformServices
        .filter((ps) => ps.status === 'running' || ps.status === 'starting' || ps.status === 'stopping' || ps.status === 'failed' || ps.isCore)
        .map((ps) => ({
          name: ps.displayName,
          status: ps.status === 'running'
            ? 'Running'
            : ps.status === 'starting'
              ? 'Starting...'
              : ps.status === 'stopping'
                ? 'Stopping...'
                : ps.status === 'failed'
                  ? 'Failed'
                  : ps.status === 'unknown'
                    ? 'Unavailable'
                  : 'Stopped',
          running: ps.status === 'running',
        })),
      traffic: {
        requests: trafficStats?.requestCount || 0,
        errors: trafficStats?.errorCount || 0,
        errorPercent: trafficStats?.errorRate || 0,
        avgResponse: trafficStats?.avgResponseTime || 0,
        reqPerMin: trafficStats?.requestsPerMinute || 0,
        status2xx: statusCounts['2xx'] || 0,
        status3xx: statusCounts['3xx'] || 0,
        status4xx: statusCounts['4xx'] || 0,
        status5xx: statusCounts['5xx'] || 0,
      },
      proxy: networkStats
        && networkStats.proxy.running !== null
        && (networkStats.proxy.state === 'running' || networkStats.proxy.state === 'stopped')
        ? {
        httpPort: String(networkStats.proxy.httpPort),
        httpsPort: String(networkStats.proxy.httpsPort),
        httpActive: networkStats.proxy.running,
        httpsActive: networkStats.proxy.running,
        routeCount: String(networkStats.proxy.routes),
      } : null,
      certificates: {
        valid: validCerts,
        expiring: expiringCerts,
        expired: expiredCerts,
      },
      dnsConfigured: status?.dns?.configured || false,
      acmeConfigured: status?.ssl?.configured || false,
      quickActions: [
        { label: 'Deploy Service', icon: 'lucide:Plus', primary: true },
        { label: 'Add Domain', icon: 'lucide:Globe' },
        { label: 'View Logs', icon: 'lucide:FileText' },
      ],
    };

    return html`
      <ob-sectionheading>Dashboard</ob-sectionheading>
      <div class="dashboard">
        <section class="section">
          <h2 class="section-title">Cluster Overview</h2>
          ${dashboardData.cluster
            ? html`<sz-status-grid-cluster .stats=${dashboardData.cluster}></sz-status-grid-cluster>`
            : html`
                <div class="status-panel">
                  ${this.systemState.resource.phase === 'loading'
                    ? 'Loading system status…'
                    : 'System status is unavailable.'}
                  <button @click=${() => void appstate.fetchSystemStatus()}>Retry</button>
                </div>
              `}
        </section>

        <section class="section">
          <h2 class="section-title">Services & Resources</h2>
          <div class="services-grid">
            ${dashboardData.resourceUsage
              ? html`<sz-resource-usage-card .data=${dashboardData.resourceUsage}></sz-resource-usage-card>`
              : html`
                  <div class="status-panel">
                    Resource usage is unavailable.
                    <button @click=${() => void appstate.fetchSystemStatus()}>Retry</button>
                  </div>
                `}
            <sz-platform-services-card
              .services=${dashboardData.platformServices}
              @service-click=${(e: CustomEvent) => this.handlePlatformServiceClick(e)}
            ></sz-platform-services-card>
          </div>
        </section>

        <section class="section">
          <h2 class="section-title">Network & Traffic</h2>
          ${this.networkState.statsResource.phase === 'stale'
            ? html`<div class="stale-warning">Showing the last known proxy status. Refresh failed.</div>`
            : ''}
          ${dashboardData.proxy
            ? html`
                <sz-status-grid-network
                  .traffic=${dashboardData.traffic}
                  .proxy=${dashboardData.proxy}
                  .certificates=${dashboardData.certificates}
                ></sz-status-grid-network>
              `
            : html`
                <div class="status-panel">
                  ${networkStats?.proxy.state === 'failed'
                    ? 'Reverse proxy status: Failed.'
                    : networkStats?.proxy.state === 'starting'
                    ? 'Reverse proxy is starting…'
                    : this.networkState.statsResource.phase === 'loading'
                      ? 'Loading reverse proxy status…'
                      : 'Reverse proxy status is unavailable.'}
                  <button @click=${() => void appstate.fetchNetworkStats()}>Retry</button>
                </div>
              `}
        </section>

        <section class="section">
          <h2 class="section-title">Infrastructure</h2>
          <sz-status-grid-infra
            ?dnsConfigured=${dashboardData.dnsConfigured}
            ?acmeConfigured=${dashboardData.acmeConfigured}
            .actions=${dashboardData.quickActions}
            @action-click=${(e: CustomEvent) => this.handleQuickAction(e)}
          ></sz-status-grid-infra>
        </section>
      </div>
    `;
  }

  private handleQuickAction(e: CustomEvent) {
    const action = e.detail?.action || e.detail?.label;
    if (action === 'Deploy Service') {
      appRouter.navigateToView('services');
    } else if (action === 'Add Domain') {
      appRouter.navigateToView('network');
    }
  }

  private handlePlatformServiceClick(e: CustomEvent) {
    // Find the platform service type from the click event
    const name = e.detail?.name;
    const ps = this.servicesState.platformServices.find(
      (p) => p.displayName === name,
    );
    if (ps) {
      // Navigate to services tab — the ObViewServices component will pick up the type
      // Store the selected platform type so the services view can open it
      appstate.servicesStatePart.setState({
        ...appstate.getRequiredState(appstate.servicesStatePart),
        currentPlatformService: ps,
      });
      appRouter.navigateToView('services');
    }
  }
}
