import '@components/InitialSetup';
import '@components/Sidebar';
import '@routes/404Page';
import '@routes/Arbor/Home';
import '@routes/Arbor/NewPost';
import '@routes/Arbor/NewThread';
import '@routes/Arbor/ThreadView';
import '@routes/Calendar';
import '@routes/Home';
import '@routes/Profile';
import '@routes/Settings';
import '@routes/Wallet';

import { getNpub, getUserProfile } from '@/ndk';
import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
import { spread } from '@open-wc/lit-helpers';
import { LitElement, css } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { keyed } from 'lit/directives/keyed.js';
import { type Ref, createRef, ref } from 'lit/directives/ref.js';
import { when } from 'lit/directives/when.js';
import { type StaticValue, html, literal } from 'lit/static-html.js';

export interface RouteParams {
  [key: string]: string;
}

interface Route {
  pattern: string;
  params: RouteParams;
  component: StaticValue;
  title?: string;
  meta?: Record<string, string>;
}

@customElement('arx-eve-router')
export default class EveRouter extends LitElement {
  private static routes: Route[] = [
    {
      pattern: 'home',
      params: {},
      component: literal`arx-eve-home`,
    },
    {
      pattern: 'calendar',
      params: {},
      component: literal`arx-calendar-route`,
    },
    {
      pattern: 'profile/:npub',
      params: {},
      component: literal`arx-profile-route`,
    },
    {
      pattern: 'arbor',
      params: {},
      component: literal`arx-arbor-home`,
    },
    {
      pattern: 'arbor/new-thread/:categoryId',
      params: {},
      component: literal`arx-arbor-thread-creator`,
    },
    {
      pattern: 'arbor/threads/:threadId',
      params: {},
      component: literal`arx-arbor-thread-view`,
    },
    {
      pattern: 'arbor/new-post/:threadId',
      params: {},
      component: literal`arx-arbor-post-creator`,
    },
    {
      pattern: 'howl',
      params: {},
      component: literal`arx-howl-route`,
    },
    {
      pattern: 'settings',
      params: {},
      component: literal`arx-settings`,
    },
    {
      pattern: 'wallet',
      params: {},
      component: literal`arx-wallet-route`,
    },
    {
      pattern: '404',
      params: {},
      component: literal`arx-404-page`,
    },
  ];

  @state()
  private history: string[] = [];

  @state()
  private currentIndex = -1;

  @state()
  private isTransitioning = false;

  @property()
  public ccnSetup = false;

  windowContentRef: Ref<HTMLDivElement> = createRef();
  pageTransitions = true;

  private beforeEachGuards: ((to: Route, from: Route | null) => boolean)[] = [];
  private afterEachHooks: ((to: Route, from: Route | null) => void)[] = [];

  @state()
  private userProfile: NDKUserProfile | undefined = undefined;

  @state()
  private userNpub = '';

  @state()
  private sidebarVisible = true;

  static override styles = css`
    :host {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      display: grid;
      grid-template-rows: auto 1fr;
      grid-template-columns: auto 1fr;
      overflow: hidden;
      transition: grid-template-columns 0.3s ease;
    }

    :host([sidebar-hidden]) {
        grid-template-columns: 0 1fr;
    }

    ::-webkit-scrollbar {
      width: 12px;
      height: 12px;
    }

    ::-webkit-scrollbar-track {
      background: var(--color-base-200);
      border-radius: var(--radius-field);
    }

    ::-webkit-scrollbar-thumb {
      background: var(--color-base-300);
      border-radius: var(--radius-field);
      border: 2px solid var(--color-base-200);
      transition: var(--transition);
    }

    ::-webkit-scrollbar-thumb:hover {
      background: var(--color-neutral);
    }
    
    .window {
      overflow: auto;
      grid-column: 2;
      grid-row: 2;
      position: relative;
    }
    
    .window::after {
      content: '';
      position: absolute;
      right: 0;
      top: 0;
      width: 10px;
      height: 100%;
      opacity: 0;
      pointer-events: none;
      background: linear-gradient(to right, transparent, rgba(0, 0, 0, 0.03));
      transition: opacity 0.3s ease;
    }
    
    .window:hover::after {
      opacity: 1;
    }

    arx-sidebar {
      grid-column: 1;
      grid-row: 1 / span 2;
      transition: width 0.3s ease, opacity 0.3s ease, padding 0.3s ease, transform 0.3s ease;
      width: 100px;
      opacity: 1;
      overflow: hidden;
      background: var(--color-base-100);
      border-right: 1px solid var(--color-base-300);
    }

    arx-sidebar.hidden {
      width: 0;
      opacity: 0;
      padding: 0;
      pointer-events: none;
      transform: translateX(-20px);
      border-right: none;
    }

    .window-content {
      max-width: 1200px;
      overflow: visible;
      height: 100%;
      margin: 0 auto;
      padding: 1rem;
      opacity: 1;
      transform-origin: left center;
      transform: perspective(1200px) translateX(0);
      transition: var(--transition);
      backface-visibility: hidden;
      filter: blur(0px);
      grid-row: 1;
    }

    .window-content::after {
      content: '';
      position: absolute;
      top: 0;
      right: 0;
      width: 4px;
      height: 100%;
      opacity: 0;
      transition: var(--transition);
    }

    .window-content.transitioning {
      overflow: hidden;
      transform: perspective(1200px) translateX(50vw);
      filter: blur(50px);
    }
    
    .window-content.transitioning::after {
      opacity: 1;
    }

    .hide-overflow {
      overflow: hidden;
    }

    arx-header {
      grid-column: 2;
      grid-row: 1;
    }

    .sidebar-toggle {
       position: fixed;
       top: 50%;
       left: 100px;
       transform: translateY(-50%);
       z-index: 1000;
       background: color-mix(in srgb, var(--color-primary) 70%, transparent);
       backdrop-filter: blur(5px);
       color: var(--color-base);
       border: none;
       width: 20px;
       height: 50px;
       border-top-right-radius: var(--radius-btn);
       border-bottom-right-radius: var(--radius-btn);
       border-top-left-radius: 0;
       border-bottom-left-radius: 0;
       cursor: pointer;
       display: flex;
       align-items: center;
       justify-content: center;
       font-size: 14px;
       transition: all var(--transition);
       box-shadow: 2px 0 5px rgba(0,0,0,0.1);
    }

    :host([sidebar-hidden]) .sidebar-toggle {
        left: 0;
        border-top-left-radius: var(--radius-btn);
        border-bottom-left-radius: var(--radius-btn);
        border-top-right-radius: 0;
        border-bottom-right-radius: 0;
    }

    .sidebar-toggle:hover {
      /* background: var(--color-primary-focus); */
      background: color-mix(in srgb, var(--color-primary) 90%, transparent);
    }
  `;

  constructor() {
    super();
    this.initializeRouter();
    this.pageTransitions = localStorage.getItem('pageTransitions') !== 'false';
    if (this.ccnSetup) window.relay.start(localStorage.getItem('encryption_key')!);
  }

  override connectedCallback(): void {
    super.connectedCallback();
    this.setupEventListeners();
    if (this.ccnSetup) {
      this.loadUserProfile();
    }
    this.updateSidebarAttribute();
  }

  override disconnectedCallback(): void {
    super.disconnectedCallback();
    window.removeEventListener('hashchange', this.handleHashChange);
    window.removeEventListener('popstate', this.handlePopState);
  }

  private initializeRouter(): void {
    const initialPath = this.currentPath;
    this.history = [initialPath];
    this.currentIndex = 0;
    this.navigate(initialPath);
  }

  private setupEventListeners(): void {
    window.addEventListener('hashchange', this.handleHashChange.bind(this));
    window.addEventListener('popstate', this.handlePopState.bind(this));
  }

  private async handleHashChange(): Promise<void> {
    const newPath = this.currentPath;
    if (newPath !== this.history[this.currentIndex]) {
      await this.requestUpdateWithTransition();
      this.updateHistory(newPath);
    }
  }

  private handlePopState(): void {
    this.requestUpdate();
  }

  private updateHistory(newPath: string): void {
    this.history = this.history.slice(0, this.currentIndex + 1);
    this.history.push(newPath);
    this.currentIndex = this.history.length - 1;
  }

  private matchRoute(pattern: string, path: string): { isMatch: boolean; params: RouteParams } {
    const patternParts = pattern.split('/').filter(Boolean);
    const pathParts = path.split('/').filter(Boolean);
    const params: RouteParams = {};

    if (patternParts.length !== pathParts.length) {
      return { isMatch: false, params };
    }

    const isMatch = patternParts.every((patternPart, index) => {
      const pathPart = pathParts[index];
      if (patternPart.startsWith(':')) {
        const paramName = patternPart.slice(1);
        params[paramName] = decodeURIComponent(pathPart);
        return true;
      }
      return patternPart === pathPart;
    });

    return { isMatch, params };
  }

  get currentPath(): string {
    const hash = window.location.hash?.slice(1);
    return hash === '' ? 'home' : hash;
  }

  get currentRoute(): Route {
    const route = EveRouter.routes.find((route) => {
      const { isMatch, params } = this.matchRoute(route.pattern, this.currentPath);
      if (isMatch) {
        route.params = params;
        return true;
      }
      return false;
    });
    return route || this.getNotFoundRoute();
  }

  private getNotFoundRoute(): Route {
    return {
      pattern: '404',
      params: {},
      component: literal`arx-404-page`,
    };
  }

  beforeEach(guard: (to: Route, from: Route | null) => boolean): void {
    this.beforeEachGuards.push(guard);
  }

  afterEach(hook: (to: Route, from: Route | null) => void): void {
    this.afterEachHooks.push(hook);
  }

  async navigate(path: string): Promise<void> {
    const from = this.currentRoute;
    window.location.hash = path;

    const to = this.currentRoute;
    const canProceed = this.beforeEachGuards.every((guard) => guard(to, from));

    if (canProceed) {
      await this.requestUpdateWithTransition();
      for (const hook of this.afterEachHooks) {
        hook(to, from);
      }

      if (to.title) {
        document.title = to.title;
      }
    }
  }

  async requestUpdateWithTransition(): Promise<void> {
    if (!this.windowContentRef.value) return this.requestUpdate();
    if (!this.pageTransitions) return this.requestUpdate();
    this.isTransitioning = true;
    this.requestUpdate();

    await new Promise((resolve) => {
      this.windowContentRef.value!.addEventListener(
        'transitionend',
        () => {
          this.isTransitioning = false;
          resolve(true);
        },
        { once: true },
      );
    });
    this.requestUpdate();
  }

  goBack(): void {
    if (this.currentIndex > 0) {
      this.currentIndex--;
      this.navigate(this.history[this.currentIndex]);
    }
  }

  goForward(): void {
    if (this.currentIndex < this.history.length - 1) {
      this.currentIndex++;
      this.navigate(this.history[this.currentIndex]);
    }
  }

  finishSetup() {
    this.ccnSetup = true;
  }

  renderSetup() {
    return html`
      <div class="window" style="grid-column: 1 / span 2;">
        <div class="window-content">
          <arx-initial-setup
            @finish=${() => this.finishSetup()}
          ></arx-initial-setup>
        </div>
      </div>
    `;
  }

  async loadUserProfile() {
    try {
      this.userNpub = await getNpub();
      this.userProfile = await getUserProfile();
    } catch (error) {
      console.error('Failed to load user profile:', error);
    }
  }

  private toggleSidebar() {
    this.sidebarVisible = !this.sidebarVisible;
    this.updateSidebarAttribute();
  }

  private updateSidebarAttribute() {
    if (this.sidebarVisible) {
      this.removeAttribute('sidebar-hidden');
    } else {
      this.setAttribute('sidebar-hidden', '');
    }
  }

  override render() {
    if (!this.ccnSetup) return this.renderSetup();

    return html`
       <button class="sidebar-toggle" @click=${this.toggleSidebar} title=${when(
         this.sidebarVisible,
         () => 'Hide Sidebar',
         () => 'Show Sidebar',
       )}>
         ${when(
           this.sidebarVisible,
           () => html`<iconify-icon icon="mdi:chevron-left"></iconify-icon>`,
           () => html`<iconify-icon icon="mdi:chevron-right"></iconify-icon>`,
         )}
       </button>
      <arx-sidebar 
        class=${classMap({ hidden: !this.sidebarVisible })}
        .currentPath=${this.currentPath}
        .userNpub=${this.userNpub}
        .userProfile=${this.userProfile}
        @navigate=${(e: CustomEvent) => this.navigate(e.detail)}
      ></arx-sidebar>
      <arx-header
        ?canGoBack=${this.currentIndex > 0}
        ?canGoForward=${this.currentIndex < this.history.length - 1}
        url="eve://${this.currentPath}"
        @navigate=${(e: CustomEvent) => this.navigate(e.detail)}
        @go-back=${this.goBack}
        @go-forward=${this.goForward}
        title="Eve"
      ></arx-header>
      <div class=${classMap({ window: true, 'hide-overflow': this.currentRoute.pattern === 'home' })}>
        <div ${ref(this.windowContentRef)} class=${classMap({ 'window-content': true, transitioning: this.isTransitioning })}>
          ${when(
            this.isTransitioning,
            () => html`<arx-loading-view></arx-loading-view>`,
            () =>
              keyed(
                this.currentRoute.params,
                html`
              <${this.currentRoute.component} 
                ${spread(this.currentRoute.params)}
                path=${this.currentPath}
                @navigate=${this.navigate}
                @go-back=${this.goBack}
                @go-forward=${this.goForward}
              ></${this.currentRoute.component}>
            `,
              ),
          )}
        </div>
      </div>
    `;
  }
}
