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

import type { GitopsViewOverview } from './views/overview/index.js';
import type { GitopsViewConnections } from './views/connections/index.js';
import type { GitopsViewProjects } from './views/projects/index.js';
import type { GitopsViewGroups } from './views/groups/index.js';
import type { GitopsViewSecrets } from './views/secrets/index.js';
import type { GitopsViewPipelines } from './views/pipelines/index.js';
import type { GitopsViewBuildlog } from './views/buildlog/index.js';
import type { GitopsViewActions } from './views/actions/index.js';
import type { GitopsViewActionlog } from './views/actionlog/index.js';
import type { GitopsViewSync } from './views/sync/index.js';

@customElement('gitops-dashboard')
export class GitopsDashboard extends DeesElement {
  @state()
  accessor loginState: appstate.ILoginState = { identity: null, isLoggedIn: false };

  @state()
  accessor uiState: appstate.IUiState = {
    activeView: 'overview',
    autoRefresh: true,
    refreshInterval: 30000,
  };

  private viewTabs = [
    { name: 'Overview', iconName: 'lucide:layoutDashboard', element: (async () => (await import('./views/overview/index.js')).GitopsViewOverview)() },
    { name: 'Connections', iconName: 'lucide:plug', element: (async () => (await import('./views/connections/index.js')).GitopsViewConnections)() },
    { name: 'Projects', iconName: 'lucide:folderGit2', element: (async () => (await import('./views/projects/index.js')).GitopsViewProjects)() },
    { name: 'Groups', iconName: 'lucide:users', element: (async () => (await import('./views/groups/index.js')).GitopsViewGroups)() },
    { name: 'Secrets', iconName: 'lucide:key', element: (async () => (await import('./views/secrets/index.js')).GitopsViewSecrets)() },
    { name: 'Managed Secrets', iconName: 'lucide:keyRound', element: (async () => (await import('./views/managedsecrets/index.js')).GitopsViewManagedSecrets)() },
    { name: 'Pipelines', iconName: 'lucide:play', element: (async () => (await import('./views/pipelines/index.js')).GitopsViewPipelines)() },
    { name: 'Build Log', iconName: 'lucide:scrollText', element: (async () => (await import('./views/buildlog/index.js')).GitopsViewBuildlog)() },
    { name: 'Actions', iconName: 'lucide:zap', element: (async () => (await import('./views/actions/index.js')).GitopsViewActions)() },
    { name: 'Action Log', iconName: 'lucide:scroll', element: (async () => (await import('./views/actionlog/index.js')).GitopsViewActionlog)() },
    { name: 'Sync', iconName: 'lucide:refreshCw', element: (async () => (await import('./views/sync/index.js')).GitopsViewSync)() },
  ];

  private resolvedViewTabs: Array<{ name: string; iconName: string; element: any }> = [];

  // Auto-refresh timer
  private autoRefreshTimer: ReturnType<typeof setInterval> | null = null;

  // WebSocket client
  private ws: WebSocket | null = null;
  private wsReconnectTimer: ReturnType<typeof setTimeout> | null = null;
  private wsIntentionalClose = false;

  constructor() {
    super();
    document.title = 'GitOps';

    const loginSubscription = appstate.loginStatePart
      .select((stateArg) => stateArg)
      .subscribe((loginState) => {
        this.loginState = loginState;
        if (loginState.isLoggedIn) {
          appstate.connectionsStatePart.dispatchAction(appstate.fetchConnectionsAction, null);
          this.connectWebSocket();
        } else {
          this.disconnectWebSocket();
        }
        this.manageAutoRefreshTimer();
      });
    this.rxSubscriptions.push(loginSubscription);

    const uiSubscription = appstate.uiStatePart
      .select((stateArg) => stateArg)
      .subscribe((uiState) => {
        this.uiState = uiState;
        this.syncAppdashView(uiState.activeView);
        this.manageAutoRefreshTimer();
      });
    this.rxSubscriptions.push(uiSubscription);
  }

  public static styles = [
    cssManager.defaultStyles,
    css`
      :host {
        display: block;
        width: 100%;
        height: 100%;
      }
      .maincontainer {
        width: 100%;
        height: 100vh;
      }
      .auto-refresh-toggle {
        position: fixed;
        bottom: 16px;
        right: 16px;
        z-index: 1000;
        background: rgba(30, 30, 50, 0.9);
        border: 1px solid rgba(255, 255, 255, 0.1);
        border-radius: 8px;
        padding: 8px 14px;
        color: #ccc;
        font-size: 12px;
        cursor: pointer;
        display: flex;
        align-items: center;
        gap: 8px;
        backdrop-filter: blur(8px);
        transition: background 0.2s;
      }
      .auto-refresh-toggle:hover {
        background: rgba(40, 40, 70, 0.95);
      }
      .auto-refresh-dot {
        width: 8px;
        height: 8px;
        border-radius: 50%;
        background: #666;
      }
      .auto-refresh-dot.active {
        background: #00ff88;
      }
    `,
  ];

  public render(): TemplateResult {
    return html`
      <div class="maincontainer">
        <dees-simple-login name="GitOps">
          <dees-simple-appdash
            name="GitOps"
            .viewTabs=${this.resolvedViewTabs}
          >
          </dees-simple-appdash>
        </dees-simple-login>
      </div>
      ${this.loginState.isLoggedIn ? html`
        <div
          class="auto-refresh-toggle"
          @click=${() => appstate.uiStatePart.dispatchAction(appstate.toggleAutoRefreshAction, null)}
        >
          <span class="auto-refresh-dot ${this.uiState.autoRefresh ? 'active' : ''}"></span>
          Auto-Refresh: ${this.uiState.autoRefresh ? 'ON' : 'OFF'}
        </div>
      ` : ''}
    `;
  }

  public async firstUpdated() {
    // Resolve async view tab imports
    this.resolvedViewTabs = await Promise.all(
      this.viewTabs.map(async (tab) => ({
        name: tab.name,
        iconName: tab.iconName,
        element: await tab.element,
      })),
    );
    this.requestUpdate();
    await this.updateComplete;

    const simpleLogin = this.shadowRoot!.querySelector('dees-simple-login') as any;
    if (simpleLogin) {
      simpleLogin.addEventListener('login', (e: CustomEvent) => {
        this.login(e.detail.data.username, e.detail.data.password);
      });
    }

    const appDash = this.shadowRoot!.querySelector('dees-simple-appdash') as any;
    if (appDash) {
      appDash.addEventListener('view-select', (e: CustomEvent) => {
        const viewName = e.detail.view.name.toLowerCase();
        if (this.uiState.activeView === viewName) return;
        appstate.uiStatePart.dispatchAction(appstate.setActiveViewAction, { view: viewName });
      });
      appDash.addEventListener('logout', async () => {
        await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
      });
    }

    // Load initial view on appdash
    if (appDash && this.resolvedViewTabs.length > 0) {
      const initialView = this.resolvedViewTabs.find(
        (t) => t.name.toLowerCase() === this.uiState.activeView,
      ) || this.resolvedViewTabs[0];
      await appDash.loadView(initialView);
    }

    // Check for stored session (persistent login state)
    const loginState = appstate.loginStatePart.getState();
    if (loginState.identity?.jwt) {
      if (loginState.identity.expiresAt > Date.now()) {
        try {
          const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
            interfaces.requests.IReq_VerifyIdentity
          >('/typedrequest', 'verifyIdentity');
          const response = await typedRequest.fire({ identity: loginState.identity });
          if (response.valid) {
            this.loginState = loginState;
            if (simpleLogin) {
              await simpleLogin.switchToSlottedContent();
            }
          } else {
            await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
          }
        } catch (err) {
          console.warn('Stored session invalid, returning to login:', err);
          await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
        }
      } else {
        await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
      }
    }
  }

  public override disconnectedCallback() {
    super.disconnectedCallback();
    this.clearAutoRefreshTimer();
    this.disconnectWebSocket();
  }

  // ============================================================================
  // Auto-refresh timer management
  // ============================================================================

  private manageAutoRefreshTimer(): void {
    this.clearAutoRefreshTimer();
    const { autoRefresh, refreshInterval } = this.uiState;
    if (autoRefresh && this.loginState.isLoggedIn) {
      this.autoRefreshTimer = setInterval(() => {
        document.dispatchEvent(new CustomEvent('gitops-auto-refresh'));
      }, refreshInterval);
    }
  }

  private clearAutoRefreshTimer(): void {
    if (this.autoRefreshTimer) {
      clearInterval(this.autoRefreshTimer);
      this.autoRefreshTimer = null;
    }
  }

  // ============================================================================
  // WebSocket client for webhook push notifications
  // ============================================================================

  private connectWebSocket(): void {
    if (this.ws) return;

    const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
    const wsUrl = `${protocol}//${location.host}`;

    try {
      this.wsIntentionalClose = false;
      this.ws = new WebSocket(wsUrl);

      this.ws.addEventListener('message', (event) => {
        try {
          const data = JSON.parse(event.data);
          // TypedSocket wraps messages; look for webhookNotification method
          if (data?.method === 'webhookNotification' || data?.type === 'webhookEvent') {
            console.log('Webhook event received:', data);
            document.dispatchEvent(new CustomEvent('gitops-auto-refresh'));
          }
        } catch {
          // Not JSON, ignore
        }
      });

      this.ws.addEventListener('close', () => {
        this.ws = null;
        if (!this.wsIntentionalClose && this.loginState.isLoggedIn) {
          this.wsReconnectTimer = setTimeout(() => {
            this.connectWebSocket();
          }, 5000);
        }
      });

      this.ws.addEventListener('error', () => {
        // Will trigger close event
      });
    } catch (err) {
      console.warn('WebSocket connection failed:', err);
    }
  }

  private disconnectWebSocket(): void {
    this.wsIntentionalClose = true;
    if (this.wsReconnectTimer) {
      clearTimeout(this.wsReconnectTimer);
      this.wsReconnectTimer = null;
    }
    if (this.ws) {
      this.ws.close();
      this.ws = null;
    }
  }

  // ============================================================================
  // Login
  // ============================================================================

  private async login(username: string, password: string) {
    const domtools = await this.domtoolsPromise;
    const simpleLogin = this.shadowRoot!.querySelector('dees-simple-login') as any;
    const form = simpleLogin?.shadowRoot?.querySelector('dees-form') as any;

    if (form) {
      form.setStatus('pending', 'Logging in...');
    }

    const newState = await appstate.loginStatePart.dispatchAction(appstate.loginAction, {
      username,
      password,
    });

    if (newState.identity) {
      if (form) {
        form.setStatus('success', 'Logged in!');
      }
      if (simpleLogin) {
        await simpleLogin.switchToSlottedContent();
      }
    } else {
      if (form) {
        form.setStatus('error', 'Login failed!');
        await domtools.convenience.smartdelay.delayFor(2000);
        form.reset();
      }
    }
  }

  private syncAppdashView(viewName: string): void {
    const appDash = this.shadowRoot?.querySelector('dees-simple-appdash') as any;
    if (!appDash || this.resolvedViewTabs.length === 0) return;
    const targetTab = this.resolvedViewTabs.find((t) => t.name.toLowerCase() === viewName);
    if (!targetTab) return;
    if (appDash.selectedView === targetTab) return;
    appDash.loadView(targetTab);
  }
}
