/* eslint-disable @typescript-eslint/member-ordering */
import {
  CUSTOM_ELEMENTS_SCHEMA,
  Component,
  ElementRef,
  NgZone,
  OnDestroy,
  computed,
  effect,
  inject,
  signal,
  viewChild
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { ActivatedRoute, Router } from '@angular/router';
import { toSignal } from '@angular/core/rxjs-interop';
import { map } from 'rxjs';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideChevronLeft, lucidePhoneCall } from '@ng-icons/lucide';
import { APP_TRANSLATE_IMPORTS } from '../../../../core/i18n';
import { ServersRailComponent } from '../../../../features/servers/servers-rail/servers-rail.component';
import { ViewportService } from '../../../../core/platform';
import { ThemeService } from '../../../theme';
import { DirectCallService } from '../../../direct-call';
import { DirectMessageService } from '../../application/services/direct-message.service';
import { DmChatPanelComponent } from './dm-chat-panel.component';
import { DmConversationsPanelComponent } from './dm-conversations-panel.component';

/** Mobile-only page identifier within the DM workspace flow. */
export type DmWorkspaceMobilePage = 'conversations' | 'chat';

const PAGE_TO_INDEX: Record<DmWorkspaceMobilePage, number> = {
  conversations: 0,
  chat: 1
};
const INDEX_TO_PAGE: DmWorkspaceMobilePage[] = ['conversations', 'chat'];

interface SwiperElement extends HTMLElement {
  swiper?: { activeIndex: number; slideTo: (index: number, speed?: number) => void };
}

@Component({
  selector: 'app-dm-workspace',
  standalone: true,
  imports: [
    CommonModule,
    NgIcon,
    DmChatPanelComponent,
    DmConversationsPanelComponent,
    ServersRailComponent,
    ...APP_TRANSLATE_IMPORTS
  ],
  viewProviders: [provideIcons({ lucideChevronLeft, lucidePhoneCall })],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  templateUrl: './dm-workspace.component.html'
})
export class DmWorkspaceComponent implements OnDestroy {
  private readonly route = inject(ActivatedRoute);
  private readonly router = inject(Router);
  private readonly theme = inject(ThemeService);
  private readonly viewport = inject(ViewportService);
  private readonly zone = inject(NgZone);
  private readonly directCalls = inject(DirectCallService);
  private lastSeenConversationId: string | null = null;
  private swiperListenerAttached: SwiperElement | null = null;
  readonly directMessages = inject(DirectMessageService);
  readonly routeConversationId = toSignal(this.route.paramMap.pipe(map((params) => params.get('conversationId'))), {
    initialValue: this.route.snapshot.paramMap.get('conversationId')
  });
  readonly layoutStyles = computed(() => this.theme.getLayoutContainerStyles('dmLayout'));
  readonly isMobile = this.viewport.isMobile;
  readonly swiperRef = viewChild<ElementRef<SwiperElement>>('swiperEl');
  readonly activeCall = computed(() => {
    const currentSession = this.directCalls.currentSession();
    const visibleSessions = this.directCalls.visibleActiveSessions();

    return visibleSessions.find((session) => session.callId === currentSession?.callId) ?? visibleSessions[0] ?? null;
  });

  /** Active page within the mobile single-pane navigation flow. Ignored on desktop. */
  readonly mobilePage = signal<DmWorkspaceMobilePage>('conversations');

  constructor() {
    effect(() => {
      const conversationId = this.routeConversationId();
      const isMobile = this.isMobile();

      if (conversationId) {
        void this.directMessages.openConversation(conversationId);

        // Only auto-advance to the chat page when the conversation actually changes.
        // Without this, pressing Back to the conversations list immediately bounces
        // us forward again because the conversation id is still the same.
        if (isMobile && conversationId !== this.lastSeenConversationId) {
          this.mobilePage.set('chat');
        }

        this.lastSeenConversationId = conversationId;
        return;
      }

      this.lastSeenConversationId = null;

      // On mobile, stay on the conversations list and let the user pick one explicitly.
      if (isMobile) {
        this.mobilePage.set('conversations');
        return;
      }

      const firstConversation = this.directMessages.conversations()[0];

      if (firstConversation) {
        void this.router.navigate(['/dm', firstConversation.id], { replaceUrl: true });
      }
    });

    // Mirror `mobilePage` into the Swiper instance so route-driven page changes and the
    // header back button actually slide the carousel.
    effect(() => {
      const el = this.swiperRef()?.nativeElement;
      const targetIndex = PAGE_TO_INDEX[this.mobilePage()];

      if (el?.swiper && el.swiper.activeIndex !== targetIndex) {
        el.swiper.slideTo(targetIndex);
      }
    });

    // Bridge Swiper's slidechange event back into `mobilePage`.
    effect((onCleanup) => {
      const el = this.swiperRef()?.nativeElement;

      if (!el || el === this.swiperListenerAttached) {
        return;
      }

      const handler = (event: Event) => {
        const detail = (event as CustomEvent).detail;
        const swiper = Array.isArray(detail) ? detail[0] : detail;
        const index = swiper?.activeIndex ?? 0;
        const page = INDEX_TO_PAGE[index] ?? 'conversations';

        this.zone.run(() => this.mobilePage.set(page));
      };

      el.addEventListener('swiperslidechange', handler);
      this.swiperListenerAttached = el;

      onCleanup(() => {
        el.removeEventListener('swiperslidechange', handler);

        if (this.swiperListenerAttached === el) {
          this.swiperListenerAttached = null;
        }
      });
    });
  }

  /** Set the active mobile page. No-op on desktop. */
  setMobilePage(page: DmWorkspaceMobilePage): void {
    this.mobilePage.set(page);
  }

  openActiveCall(): void {
    const call = this.activeCall();

    if (call) {
      void this.directCalls.openCallView(call.callId);
    }
  }

  ngOnDestroy(): void {
    this.directMessages.closeConversationView(this.routeConversationId());
  }
}

