import { ChangeDetectionStrategy, Component, ElementRef, OnInit, ViewChild, computed, inject, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TranslatePipe } from '../../../i18n/translate.pipe';
import { TranslateService } from '../../../i18n/translate.service';
import { MediaLibraryFacade, MediaViewMode } from './facade/media-library.facade';
import { MediaAsset, MediaAssetKind, MediaSort } from '../../../core/media/models/media-asset.model';
import { MediaUsageService } from '../../../core/media/media-usage.service';
import { ButtonComponent } from '../../../shared/ui/button/button.component';
import { InputComponent } from '../../../shared/ui/input/input.component';
import { EmptyStateComponent } from '../../../shared/ui/empty-state/empty-state.component';
import { DialogComponent } from '../../../shared/ui/dialog/dialog.component';
import { PaginationComponent } from '../../../shared/ui/pagination/pagination.component';
import { SkeletonComponent } from '../../../shared/ui/skeleton/skeleton.component';
import { SelectComponent, SelectOption } from '../../../shared/ui/select/select.component';
import { DashboardMetricComponent } from '../../admin/dashboard/components/dashboard-metric.component';
import { ProjectEditorFacade } from '../../project-editor/facade/project-editor.facade';
import { AssetTileComponent } from './components/asset-tile/asset-tile.component';
import { AssetDetailsDrawerComponent, AssetDetailsPatch } from './components/asset-details-drawer/asset-details-drawer.component';

const PAGE_SIZE = 24;

@Component({
  selector: 'app-media-library-page',
  standalone: true,
  imports: [
    TranslatePipe,
    FormsModule,
    ButtonComponent,
    InputComponent,
    EmptyStateComponent,
    DialogComponent,
    PaginationComponent,
    SkeletonComponent,
    SelectComponent,
    DashboardMetricComponent,
    AssetTileComponent,
    AssetDetailsDrawerComponent,
  ],
  templateUrl: './media-library-page.component.html',
  styleUrl: './media-library-page.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MediaLibraryPageComponent implements OnInit {
  protected readonly facade = inject(MediaLibraryFacade);
  private readonly usageService = inject(MediaUsageService);
  private readonly projectEditor = inject(ProjectEditorFacade);
  private readonly translate = inject(TranslateService);

  @ViewChild('fileInput') private fileInput?: ElementRef<HTMLInputElement>;

  protected readonly pendingDelete = signal<MediaAsset | null>(null);
  protected readonly bulkDeleteConfirmOpen = signal(false);
  protected readonly detailsAsset = signal<MediaAsset | null>(null);
  protected readonly dragActive = signal(false);
  protected readonly totalPages = () => Math.max(1, Math.ceil(this.facade.total() / PAGE_SIZE));

  protected readonly kindOptions = computed<SelectOption[]>(() => [
    { value: 'all', label: this.translate.t('mediaLibrary.allTypes') },
    { value: 'image', label: this.translate.t('mediaLibrary.typeImage') },
    { value: 'svg', label: this.translate.t('mediaLibrary.typeSvg') },
    { value: 'pdf', label: this.translate.t('mediaLibrary.typePdf') },
  ]);

  protected readonly sortOptions = computed<SelectOption[]>(() => [
    { value: 'recent', label: this.translate.t('mediaLibrary.sortRecent') },
    { value: 'name', label: this.translate.t('mediaLibrary.sortName') },
    { value: 'size', label: this.translate.t('mediaLibrary.sortSize') },
  ]);

  private readonly bootstrap = this.projectEditor.bootstrap;

  /** Usage lookups are computed per visible page, not the whole library, to avoid walking the bootstrap config thousands of times for large libraries. */
  private readonly usageByAssetId = computed<Map<string, number>>(() => {
    const bootstrap = this.bootstrap();
    const map = new Map<string, number>();
    for (const asset of this.facade.items()) {
      map.set(asset.id, this.usageService.findUsages(bootstrap, asset.url).length);
    }
    return map;
  });

  protected readonly totalAssets = computed(() => this.facade.total());
  protected readonly imagesCount = computed(() => this.facade.items().filter(a => a.mimeType.startsWith('image/')).length);
  protected readonly svgCount = computed(() => this.facade.items().filter(a => a.mimeType === 'image/svg+xml').length);
  protected readonly logosCount = computed(() => {
    const bootstrap = this.bootstrap();
    return this.facade.items().filter(a => this.usageService.findUsages(bootstrap, a.url).some(u => u.labelKey === 'mediaLibrary.usage.brand')).length;
  });
  protected readonly unusedCount = computed(() => {
    const usage = this.usageByAssetId();
    return this.facade.items().filter(a => (usage.get(a.id) ?? 0) === 0).length;
  });
  protected readonly storageBytes = computed(() => this.facade.items().reduce((sum, a) => sum + a.size, 0));
  protected readonly altCoveragePercent = computed(() => {
    const images = this.facade.items().filter(a => a.mimeType.startsWith('image/'));
    if (images.length === 0) return 100;
    const withAlt = images.filter(a => a.decorative || !!a.altText?.['en']).length;
    return Math.round((withAlt / images.length) * 100);
  });

  ngOnInit(): void {
    void this.facade.load();
  }

  protected usageCountFor(asset: MediaAsset): number {
    return this.usageByAssetId().get(asset.id) ?? 0;
  }

  protected isUnused(asset: MediaAsset): boolean {
    return this.usageCountFor(asset) === 0;
  }

  protected missingAlt(asset: MediaAsset): boolean {
    return !asset.decorative && !asset.altText?.['en'];
  }

  protected formatSize(bytes: number): string {
    if (bytes < 1024) return `${bytes} B`;
    if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
    return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
  }

  protected setViewMode(mode: MediaViewMode): void {
    this.facade.setViewMode(mode);
  }

  protected setKind(value: string): void {
    this.facade.setKind(value === 'all' ? null : (value as MediaAssetKind));
  }

  protected setSort(value: string): void {
    this.facade.setSort(value as MediaSort);
  }

  protected triggerFileInput(): void {
    this.fileInput?.nativeElement.click();
  }

  protected async onFileSelected(event: Event): Promise<void> {
    const input = event.target as HTMLInputElement;
    const files = input.files ? Array.from(input.files) : [];
    input.value = '';
    for (const file of files) {
      await this.facade.upload(file);
    }
  }

  protected onDragOver(event: DragEvent): void {
    event.preventDefault();
    this.dragActive.set(true);
  }

  protected onDragLeave(): void {
    this.dragActive.set(false);
  }

  protected async onDrop(event: DragEvent): Promise<void> {
    event.preventDefault();
    this.dragActive.set(false);
    const files = event.dataTransfer?.files ? Array.from(event.dataTransfer.files) : [];
    for (const file of files) {
      await this.facade.upload(file);
    }
  }

  protected friendlyUploadError(message: string | null): string | null {
    if (!message) return null;
    if (message.includes('exceeds')) return this.translate.t('mediaLibrary.errorTooLarge');
    if (message.includes('Unsupported file type')) return this.translate.t('mediaLibrary.errorUnsupportedType');
    return this.translate.t('mediaLibrary.errorGeneric');
  }

  protected openDetails(asset: MediaAsset): void {
    this.detailsAsset.set(asset);
  }

  protected closeDetails(): void {
    this.detailsAsset.set(null);
  }

  protected detailsUsages() {
    const asset = this.detailsAsset();
    return asset ? this.usageService.findUsages(this.bootstrap(), asset.url) : [];
  }

  protected async saveDetails(patch: AssetDetailsPatch): Promise<void> {
    const asset = this.detailsAsset();
    if (!asset) return;
    await this.facade.updateDetails(asset.id, patch);
    const refreshed = this.facade.items().find(a => a.id === asset.id) ?? null;
    this.detailsAsset.set(refreshed);
  }

  protected confirmDelete(asset: MediaAsset): void {
    this.pendingDelete.set(asset);
  }

  protected cancelDelete(): void {
    this.pendingDelete.set(null);
  }

  protected async proceedDelete(): Promise<void> {
    const asset = this.pendingDelete();
    if (!asset) return;
    await this.facade.remove(asset.id);
    this.pendingDelete.set(null);
    if (this.detailsAsset()?.id === asset.id) {
      this.closeDetails();
    }
  }

  protected selectedAssets(): MediaAsset[] {
    return this.facade.items().filter(a => this.facade.isSelected(a.id));
  }

  protected bulkDelete(): void {
    if (this.selectedAssets().length === 0) return;
    this.bulkDeleteConfirmOpen.set(true);
  }

  protected async proceedBulkDelete(): Promise<void> {
    const ids = this.selectedAssets().map(a => a.id);
    this.bulkDeleteConfirmOpen.set(false);
    if (ids.length === 0) return;
    await this.facade.bulkDelete(ids);
  }

  protected bulkDownload(): void {
    this.facade.downloadAssets(this.selectedAssets());
  }

  protected bulkExportMetadata(): void {
    this.facade.exportMetadata(this.selectedAssets());
  }
}
