/* eslint-disable @typescript-eslint/member-ordering */
import {
  Component,
  inject,
  signal,
  computed,
  effect,
  untracked,
  HostListener,
  viewChild
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Store } from '@ngrx/store';
import { NgIcon, provideIcons } from '@ng-icons/core';
import {
  lucideX,
  lucideBug,
  lucideBell,
  lucideDownload,
  lucideGlobe,
  lucideAudioLines,
  lucidePalette,
  lucidePackage,
  lucideSettings,
  lucideTerminal,
  lucideUsers,
  lucideBan,
  lucideShield
} from '@ng-icons/lucide';

import { SettingsModalService, SettingsPage } from '../../../core/services/settings-modal.service';
import { RealtimeSessionFacade } from '../../../core/realtime';
import { selectSavedRooms, selectCurrentRoom } from '../../../store/rooms/rooms.selectors';
import { selectCurrentUser } from '../../../store/users/users.selectors';
import { Room, UserRole } from '../../../shared-kernel';
import { NotificationsSettingsComponent } from '../../../domains/notifications';
import { PluginManagerComponent } from '../../../domains/plugins/feature/plugin-manager/plugin-manager.component';
import { resolveLegacyRole, resolveRoomPermission } from '../../../domains/access-control';

import { GeneralSettingsComponent } from './general-settings/general-settings.component';
import { NetworkSettingsComponent } from './network-settings/network-settings.component';
import { VoiceSettingsComponent } from './voice-settings/voice-settings.component';
import { ServerSettingsComponent } from './server-settings/server-settings.component';
import { MembersSettingsComponent } from './members-settings/members-settings.component';
import { BansSettingsComponent } from './bans-settings/bans-settings.component';
import { PermissionsSettingsComponent } from './permissions-settings/permissions-settings.component';
import { DebuggingSettingsComponent } from './debugging-settings/debugging-settings.component';
import { UpdatesSettingsComponent } from './updates-settings/updates-settings.component';
import { LocalApiSettingsComponent } from './local-api-settings/local-api-settings.component';
import { DataSettingsComponent } from './data-settings/data-settings.component';
import { THIRD_PARTY_LICENSES, type ThirdPartyLicense } from './third-party-licenses';
import {
  ThemeLibraryService,
  ThemeNodeDirective,
  ThemeService
} from '../../../domains/theme';

@Component({
  selector: 'app-settings-modal',
  standalone: true,
  imports: [
    CommonModule,
    FormsModule,
    NgIcon,
    GeneralSettingsComponent,
    NetworkSettingsComponent,
    NotificationsSettingsComponent,
    PluginManagerComponent,
    VoiceSettingsComponent,
    UpdatesSettingsComponent,
    LocalApiSettingsComponent,
    DataSettingsComponent,
    DebuggingSettingsComponent,
    ServerSettingsComponent,
    MembersSettingsComponent,
    BansSettingsComponent,
    PermissionsSettingsComponent,
    ThemeNodeDirective
  ],
  viewProviders: [
    provideIcons({
      lucideX,
      lucideBug,
      lucideBell,
      lucideDownload,
      lucideGlobe,
      lucideAudioLines,
      lucidePalette,
      lucidePackage,
      lucideSettings,
      lucideTerminal,
      lucideUsers,
      lucideBan,
      lucideShield
    })
  ],
  templateUrl: './settings-modal.component.html'
})
export class SettingsModalComponent {
  readonly modal = inject(SettingsModalService);
  private store = inject(Store);
  private webrtc = inject(RealtimeSessionFacade);
  private theme = inject(ThemeService);
  private themeLibrary = inject(ThemeLibraryService);
  readonly thirdPartyLicenses: readonly ThirdPartyLicense[] = THIRD_PARTY_LICENSES;
  private lastRequestedServerId: string | null = null;

  private permissionsComponent = viewChild<PermissionsSettingsComponent>('permissionsComp');

  savedRooms = this.store.selectSignal(selectSavedRooms);
  currentRoom = this.store.selectSignal(selectCurrentRoom);
  currentUser = this.store.selectSignal(selectCurrentUser);

  isOpen = this.modal.isOpen;
  activePage = this.modal.activePage;
  themeStudioFullscreen = this.modal.themeStudioFullscreen;
  themeStudioMinimized = this.modal.themeStudioMinimized;
  isThemeStudioFullscreen = computed(() => this.activePage() === 'theme' && this.themeStudioFullscreen());
  activeThemeName = this.theme.activeThemeName;
  savedThemesAvailable = this.themeLibrary.isAvailable;
  savedThemes = this.themeLibrary.entries;
  savedThemesBusy = this.themeLibrary.isBusy;
  selectedSavedTheme = this.themeLibrary.selectedEntry;

  readonly globalPages: { id: SettingsPage; label: string; icon: string }[] = [
    { id: 'general', label: 'General', icon: 'lucideSettings' },
    { id: 'plugins', label: 'Client plugins', icon: 'lucidePackage' },
    { id: 'theme', label: 'Theme Studio', icon: 'lucidePalette' },
    { id: 'network', label: 'Network', icon: 'lucideGlobe' },
    { id: 'notifications', label: 'Notifications', icon: 'lucideBell' },
    { id: 'voice', label: 'Voice & Audio', icon: 'lucideAudioLines' },
    { id: 'updates', label: 'Updates', icon: 'lucideDownload' },
    { id: 'localApi', label: 'Local API', icon: 'lucideTerminal' },
    { id: 'data', label: 'Data', icon: 'lucideDownload' },
    { id: 'debugging', label: 'Debugging', icon: 'lucideBug' }
  ];
  readonly serverPages: { id: SettingsPage; label: string; icon: string }[] = [
    { id: 'server', label: 'Server', icon: 'lucideSettings' },
    { id: 'serverPlugins', label: 'Server plugins', icon: 'lucidePackage' },
    { id: 'members', label: 'Members', icon: 'lucideUsers' },
    { id: 'bans', label: 'Bans', icon: 'lucideBan' },
    { id: 'permissions', label: 'Permissions', icon: 'lucideShield' }
  ];

  manageableRooms = computed<Room[]>(() => {
    const user = this.currentUser();

    if (!user)
      return [];

    const roomsById = new Map(this.savedRooms().map((room) => [room.id, room]));
    const currentRoom = this.currentRoom();

    if (currentRoom) {
      roomsById.set(currentRoom.id, currentRoom);
    }

    return Array.from(roomsById.values()).filter((room) => {
      const viewedRoom = currentRoom?.id === room.id ? currentRoom : room;
      const role = resolveLegacyRole(viewedRoom, user);

      return (
        role === 'host' ||
        resolveRoomPermission(viewedRoom, user, 'manageServer') ||
        resolveRoomPermission(viewedRoom, user, 'manageRoles') ||
        resolveRoomPermission(viewedRoom, user, 'manageChannels') ||
        resolveRoomPermission(viewedRoom, user, 'manageIcon') ||
        resolveRoomPermission(viewedRoom, user, 'manageBans') ||
        resolveRoomPermission(viewedRoom, user, 'kickMembers') ||
        resolveRoomPermission(viewedRoom, user, 'banMembers')
      );
    });
  });

  selectedServerId = signal<string | null>(null);
  selectedServer = computed<Room | null>(() => {
    const id = this.selectedServerId();
    const currentRoom = this.currentRoom();

    if (!id)
      return null;

    return currentRoom?.id === id ? currentRoom : (this.manageableRooms().find((room) => room.id === id) ?? null);
  });

  showServerTabs = computed(() => {
    return this.manageableRooms().length > 0 && !!this.selectedServerId();
  });

  selectedServerRole = computed<UserRole | null>(() => {
    const server = this.selectedServer();
    const user = this.currentUser();

    if (!server || !user)
      return null;

    return resolveLegacyRole(this.currentRoom()?.id === server.id ? (this.currentRoom() ?? server) : server, user);
  });

  canAccessSelectedServer = computed(() => {
    const server = this.selectedServer();
    const user = this.currentUser();

    return (
      !!server &&
      !!user &&
      (resolveLegacyRole(server, user) === 'host' ||
        resolveRoomPermission(server, user, 'manageServer') ||
        resolveRoomPermission(server, user, 'manageRoles') ||
        resolveRoomPermission(server, user, 'manageChannels') ||
        resolveRoomPermission(server, user, 'manageIcon') ||
        resolveRoomPermission(server, user, 'manageBans') ||
        resolveRoomPermission(server, user, 'kickMembers') ||
        resolveRoomPermission(server, user, 'banMembers'))
    );
  });

  canManageSelectedMembers = computed(() => {
    const server = this.selectedServer();
    const user = this.currentUser();

    return (
      !!server &&
      !!user &&
      (resolveLegacyRole(server, user) === 'host' ||
        resolveRoomPermission(server, user, 'manageRoles') ||
        resolveRoomPermission(server, user, 'kickMembers') ||
        resolveRoomPermission(server, user, 'banMembers'))
    );
  });

  canManageSelectedBans = computed(() => {
    const server = this.selectedServer();
    const user = this.currentUser();

    return !!server && !!user && (resolveLegacyRole(server, user) === 'host' || resolveRoomPermission(server, user, 'manageBans'));
  });

  canManageSelectedPermissions = computed(() => {
    const server = this.selectedServer();
    const user = this.currentUser();

    return (
      !!server &&
      !!user &&
      (resolveLegacyRole(server, user) === 'host' ||
        resolveRoomPermission(server, user, 'manageRoles') ||
        resolveRoomPermission(server, user, 'manageServer'))
    );
  });

  isSelectedServerOwner = computed(() => {
    return this.selectedServerRole() === 'host';
  });

  canManageSelectedServerSettings = computed(() => {
    const server = this.selectedServer();
    const user = this.currentUser();

    return !!server && !!user && (resolveLegacyRole(server, user) === 'host' || resolveRoomPermission(server, user, 'manageServer'));
  });

  canManageSelectedServerIcon = computed(() => {
    const server = this.selectedServer();
    const user = this.currentUser();

    return !!server && !!user && (resolveLegacyRole(server, user) === 'host' || resolveRoomPermission(server, user, 'manageIcon'));
  });

  isSelectedServerCurrent = computed(() => {
    const selectedServerId = this.selectedServerId();
    const currentRoomId = this.currentRoom()?.id ?? null;

    return !!selectedServerId && selectedServerId === currentRoomId;
  });

  animating = signal(false);
  showThirdPartyLicenses = signal(false);

  constructor() {
    effect(() => {
      if (!this.isOpen()) {
        this.lastRequestedServerId = null;
        return;
      }

      const rooms = this.manageableRooms();
      const targetId = this.modal.targetServerId();
      const currentRoomId = this.currentRoom()?.id ?? null;
      const selectedId = this.selectedServerId();
      const hasSelected = !!selectedId && rooms.some((room) => room.id === selectedId);

      if (!hasSelected) {
        const fallbackId =
          [targetId, currentRoomId].find((candidateId) => !!candidateId && rooms.some((room) => room.id === candidateId)) ?? rooms[0]?.id ?? null;

        this.selectedServerId.set(fallbackId);
      }

      this.animating.set(true);
    });

    effect(() => {
      if (!this.isOpen() || this.activePage() !== 'theme' || !this.savedThemesAvailable()) {
        return;
      }

      untracked(() => {
        void this.refreshSavedThemes();
      });
    });

    effect(() => {
      const server = this.selectedServer();

      if (server) {
        const permsComp = this.permissionsComponent();

        if (permsComp) {
          permsComp.loadPermissions(server);
        }
      }
    });

    effect(() => {
      if (!this.isOpen())
        return;

      const serverId = this.selectedServerId();

      if (!serverId || this.lastRequestedServerId === serverId)
        return;

      this.lastRequestedServerId = serverId;

      for (const peerId of this.webrtc.getConnectedPeers()) {
        try {
          this.webrtc.sendToPeer(peerId, {
            type: 'server-state-request',
            roomId: serverId
          });
        } catch {
          /* peer may have disconnected */
        }
      }
    });
  }

  @HostListener('document:keydown.escape')
  onEscapeKey(): void {
    if (this.showThirdPartyLicenses()) {
      this.closeThirdPartyLicenses();
      return;
    }

    if (this.isThemeStudioFullscreen()) {
      this.modal.minimizeThemeStudio();
      return;
    }

    if (this.isOpen()) {
      this.close();
    }
  }

  close(): void {
    this.showThirdPartyLicenses.set(false);
    this.animating.set(false);
    setTimeout(() => this.modal.close(), 200);
  }

  closeForExternalNavigation(): void {
    this.showThirdPartyLicenses.set(false);
    this.animating.set(false);
    this.modal.close();
  }

  openThirdPartyLicenses(): void {
    this.showThirdPartyLicenses.set(true);
  }

  closeThirdPartyLicenses(): void {
    this.showThirdPartyLicenses.set(false);
  }

  navigate(page: SettingsPage): void {
    this.modal.navigate(page);
  }

  openThemeStudio(): void {
    this.modal.openThemeStudio();
  }

  async refreshSavedThemes(): Promise<void> {
    await this.themeLibrary.refresh();
    this.syncSavedThemeSelectionToActiveTheme();
  }

  async onSavedThemeSelect(event: Event): Promise<void> {
    const select = event.target as HTMLSelectElement;
    const fileName = select.value || null;

    this.themeLibrary.select(fileName);

    if (!fileName) {
      return;
    }

    const applied = await this.themeLibrary.useSelectedTheme();

    if (!applied) {
      this.syncSavedThemeSelectionToActiveTheme();
    }
  }

  async editSelectedSavedTheme(): Promise<void> {
    const opened = await this.themeLibrary.openSelectedThemeInDraft();

    if (opened) {
      this.modal.openThemeStudio();
    }
  }

  onBackdropClick(): void {
    this.close();
  }

  onServerSelect(event: Event): void {
    const select = event.target as HTMLSelectElement;

    this.selectedServerId.set(select.value || null);
  }

  restoreDefaultTheme(): void {
    this.theme.resetToDefault('button');
    this.syncSavedThemeSelectionToActiveTheme();
    this.navigate('theme');
  }

  private syncSavedThemeSelectionToActiveTheme(): void {
    const matchingTheme = this.savedThemes().find((entry) => entry.isValid && entry.themeName === this.activeThemeName()) ?? null;

    this.themeLibrary.select(matchingTheme?.fileName ?? null);
  }
}
