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

@customElement('ob-view-network')
export class ObViewNetwork extends DeesElement {
  @state()
  accessor networkState: appstate.INetworkState = {
    targets: [],
    stats: null,
    statsResource: { phase: 'idle', error: null, lastSuccessAt: null },
    trafficStats: null,
    dnsRecords: [],
    domains: [],
    gatewayDomains: [],
    gatewayDnsRecords: [],
    certificates: [],
  };

  @state()
  accessor currentTab: 'proxy' | 'dns' | 'domains' | 'domain-detail' = 'proxy';

  @state()
  accessor selectedDomain: string = '';

  constructor() {
    super();

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

  public static styles = [
    cssManager.defaultStyles,
    shared.viewHostCss,
    css`
      .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')};
      }
    `,
  ];

  async connectedCallback() {
    super.connectedCallback();
    await Promise.allSettled([
      appstate.dispatchProtectedAction(appstate.fetchNetworkTargetsAction, null),
      appstate.fetchNetworkStats(),
      appstate.dispatchProtectedAction(appstate.fetchTrafficStatsAction, null),
      appstate.dispatchProtectedAction(appstate.fetchDnsRecordsAction, null),
      appstate.dispatchProtectedAction(appstate.fetchDomainsAction, null),
      appstate.dispatchProtectedAction(appstate.fetchCertificatesAction, null),
    ]);
  }

  public render(): TemplateResult {
    switch (this.currentTab) {
      case 'dns':
        return this.renderDnsView();
      case 'domains':
        return this.renderDomainsView();
      case 'domain-detail':
        return this.renderDomainDetailView();
      default:
        return this.renderProxyView();
    }
  }

  private renderProxyView(): TemplateResult {
    const stats = this.networkState.stats;
    const resource = this.networkState.statsResource;
    if (!stats || stats.proxy.running === null || stats.proxy.state === 'failed') {
      return html`
        <ob-sectionheading>Network</ob-sectionheading>
        ${resource.phase === 'stale'
          ? html`<div class="stale-warning">Showing the last known proxy status. Refresh failed.</div>`
          : ''}
        <div class="status-panel">
          ${stats?.proxy.state === 'failed'
            ? 'Reverse proxy status: Failed.'
            : stats?.proxy.state === 'starting'
            ? 'Reverse proxy is starting…'
            : resource.phase === 'loading'
              ? 'Loading reverse proxy status…'
              : 'Reverse proxy status is unavailable.'}
          <button @click=${() => void appstate.fetchNetworkStats()}>Retry</button>
        </div>
      `;
    }

    return html`
      <ob-sectionheading>Network</ob-sectionheading>
      ${resource.phase === 'stale'
        ? html`<div class="stale-warning">Showing the last known proxy status. Refresh failed.</div>`
        : ''}
      <sz-network-proxy-view
        .proxyStatus=${stats.proxy.running ? 'running' : 'stopped'}
        .routeCount=${String(stats.proxy.routes)}
        .certificateCount=${String(stats.proxy.certificates)}
        .targetCount=${String(this.networkState.targets.length)}
        .targets=${this.networkState.targets.map((targetArg) => ({
          type: targetArg.type,
          name: targetArg.name,
          domain: targetArg.domain,
          target: `${targetArg.targetHost}:${targetArg.targetPort}`,
          status: targetArg.status,
        }))}
        .logs=${[]}
        @refresh=${() => {
          void appstate.dispatchProtectedAction(appstate.fetchNetworkTargetsAction, null);
          void appstate.fetchNetworkStats();
        }}
      ></sz-network-proxy-view>
    `;
  }

  private renderDnsView(): TemplateResult {
    return html`
      <ob-sectionheading>DNS Records</ob-sectionheading>
      <sz-network-dns-view
        .records=${this.networkState.dnsRecords}
        @sync=${() => {
          appstate.dispatchProtectedAction(appstate.syncDnsAction, null);
        }}
        @delete=${(e: CustomEvent) => {
          console.log('Delete DNS record:', e.detail);
        }}
      ></sz-network-dns-view>
    `;
  }

  private renderDomainsView(): TemplateResult {
    const certs = this.networkState.certificates;
    return html`
      <ob-sectionheading>Domains</ob-sectionheading>
      <sz-network-domains-view
        .domains=${this.networkState.domains.map((d) => {
          const domainName = d.domain.domain;
          const cert = certs.find((c) => c.certDomain === domainName);
          let certStatus: 'valid' | 'expiring' | 'expired' | 'pending' = 'pending';
          if (cert) {
            if (!cert.isValid) certStatus = 'expired';
            else if (cert.expiryDate && cert.expiryDate - Date.now() < 30 * 24 * 60 * 60 * 1000)
              certStatus = 'expiring';
            else certStatus = 'valid';
          }
          return {
            domain: domainName,
            provider: d.domain.dnsProvider || 'manual',
            serviceCount: d.serviceCount,
            certificateStatus: certStatus,
          };
        })}
        @sync=${() => {
          appstate.dispatchProtectedAction(appstate.fetchDomainsAction, null);
        }}
        @view=${(e: CustomEvent) => {
          this.selectedDomain = e.detail.domain || e.detail;
          this.currentTab = 'domain-detail';
        }}
      ></sz-network-domains-view>
    `;
  }

  private renderDomainDetailView(): TemplateResult {
    const domainDetail = this.networkState.domains.find(
      (d) => d.domain.domain === this.selectedDomain,
    );
    const cert = this.networkState.certificates.find(
      (c) => c.certDomain === this.selectedDomain,
    );

    return html`
      <ob-sectionheading>Domain Details</ob-sectionheading>
      <sz-domain-detail-view
        .domain=${domainDetail
          ? {
              id: this.selectedDomain,
              name: this.selectedDomain,
              status: 'active',
              verified: true,
              createdAt: '',
            }
          : null}
        .certificate=${cert
          ? {
              id: cert.domainId,
              domain: cert.certDomain,
              issuer: cert.issuer,
              validFrom: cert.createdAt ? new Date(cert.createdAt).toISOString() : '',
              validUntil: cert.expiryDate ? new Date(cert.expiryDate).toISOString() : '',
              daysRemaining: cert.expiryDate
                ? Math.floor((cert.expiryDate - Date.now()) / (24 * 60 * 60 * 1000))
                : 0,
              status: cert.isValid ? 'valid' : 'expired',
              autoRenew: true,
            }
          : null}
        .dnsRecords=${this.networkState.dnsRecords
          .filter((r) => r.domain?.includes(this.selectedDomain))
          .map((r) => ({
            id: r.id || '',
            type: r.type,
            name: r.domain,
            value: r.value,
            ttl: 3600,
          }))}
        @renew-certificate=${() => {
          appstate.dispatchProtectedAction(appstate.renewCertificateAction, {
            domain: this.selectedDomain,
          });
        }}
      ></sz-domain-detail-view>
    `;
  }
}
