import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AdminCategory } from '../models/admin-category.model';
import { AdminCategoryColumn, AdminCategoryHealth, AdminCategoriesDashboardStats, AdminCategoriesDensity, AdminCategoriesViewMode, ALL_CATEGORY_COLUMNS } from '../facade/admin-categories.facade';
import { TranslatePipe } from '../../../../i18n/translate.pipe';
import { ButtonComponent } from '../../../../shared/ui/button/button.component';
import { InputComponent } from '../../../../shared/ui/input/input.component';
import { BadgeComponent } from '../../../../shared/ui/badge/badge.component';
import { TableComponent } from '../../../../shared/ui/table/table.component';
import { EmptyStateComponent } from '../../../../shared/ui/empty-state/empty-state.component';
import { SkeletonComponent } from '../../../../shared/ui/skeleton/skeleton.component';
import { CardComponent } from '../../../../shared/ui/card/card.component';
import { DialogComponent } from '../../../../shared/ui/dialog/dialog.component';
import { MediaPickerComponent } from '../../../../shared/media/media-picker/media-picker.component';
import { MediaAsset } from '../../../../core/media/models/media-asset.model';
import { CategoryHealthWidgetComponent, CategoryHealthItem } from './category-health-widget/category-health-widget.component';
import { CategoriesDashboardComponent } from './categories-dashboard/categories-dashboard.component';
import { IconComponent } from '../../../../shared/ui/icon/icon.component';

export interface AdminCategoryTreeRow {
  category: AdminCategory;
  depth: number;
  hasChildren: boolean;
}

@Component({
  selector: 'app-admin-categories-list',
  standalone: true,
  imports: [
    FormsModule,
    TranslatePipe,
    ButtonComponent,
    InputComponent,
    BadgeComponent,
    TableComponent,
    EmptyStateComponent,
    SkeletonComponent,
    CardComponent,
    DialogComponent,
    MediaPickerComponent,
    CategoryHealthWidgetComponent,
    CategoriesDashboardComponent,
    IconComponent,
  ],
  templateUrl: './admin-categories-list.component.html',
  styleUrls: ['./admin-categories-list.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AdminCategoriesListComponent {
  @Input() treeRows: AdminCategoryTreeRow[] = [];
  @Input() flatCategories: AdminCategory[] = [];
  @Input() filters!: { search: string; visibility: 'all' | 'visible' | 'hidden'; includeDeleted: boolean };
  @Input() loading = false;
  @Input() error: string | null = null;
  @Input() viewMode: AdminCategoriesViewMode = 'tree';
  @Input() density: AdminCategoriesDensity = 'comfortable';
  @Input() visibleColumns: AdminCategoryColumn[] = [...ALL_CATEGORY_COLUMNS];
  @Input() selectedIds: string[] = [];
  @Input() dashboardStats: AdminCategoriesDashboardStats | null = null;
  @Input() health!: (category: AdminCategory) => AdminCategoryHealth;
  @Input() isExpanded!: (id: string) => boolean;
  @Input() canDelete!: (id: string) => boolean;
  @Input() allCategories: AdminCategory[] = [];

  @Output() filtersChange = new EventEmitter<Partial<{ search: string; visibility: 'all' | 'visible' | 'hidden'; includeDeleted: boolean }>>();
  @Output() create = new EventEmitter<void>();
  @Output() edit = new EventEmitter<string>();
  @Output() delete = new EventEmitter<string>();
  @Output() restore = new EventEmitter<string>();
  @Output() toggleVisible = new EventEmitter<{ id: string; visible: boolean }>();
  @Output() reorder = new EventEmitter<{ id: string; targetId: string }>();
  @Output() toggleExpand = new EventEmitter<string>();
  @Output() jumpToParent = new EventEmitter<string>();
  @Output() expandAll = new EventEmitter<void>();
  @Output() collapseAll = new EventEmitter<void>();
  @Output() selectionChange = new EventEmitter<{ id: string; checked: boolean }>();
  @Output() selectAll = new EventEmitter<boolean>();
  @Output() bulkVisibility = new EventEmitter<boolean>();
  @Output() bulkDelete = new EventEmitter<void>();
  @Output() bulkDuplicate = new EventEmitter<void>();
  @Output() bulkAssignParent = new EventEmitter<string | null>();
  @Output() bulkAssignImage = new EventEmitter<string>();
  @Output() bulkExport = new EventEmitter<void>();
  @Output() viewModeChange = new EventEmitter<AdminCategoriesViewMode>();
  @Output() densityChange = new EventEmitter<AdminCategoriesDensity>();
  @Output() columnToggle = new EventEmitter<{ column: AdminCategoryColumn; visible: boolean }>();

  protected readonly allColumns = ALL_CATEGORY_COLUMNS;
  protected readonly columnsPanelOpen = signal(false);
  protected readonly assignParentOpen = signal(false);
  protected readonly imagePickerOpen = signal(false);

  private draggedId: string | null = null;
  protected focusedRowIndex = signal(0);

  isSelected(id: string): boolean {
    return this.selectedIds.includes(id);
  }

  // Keyboard-accessible equivalent of the native HTML5 drag-and-drop reorder
  // above (WCAG 2.1.1) - swaps a row with its adjacent sibling using the same
  // `reorder` output the mouse path already emits, so no facade/business
  // logic changes.
  private siblingRows(row: AdminCategoryTreeRow): AdminCategoryTreeRow[] {
    return this.treeRows.filter(candidate => candidate.category.parentId === row.category.parentId);
  }

  canMoveUp(row: AdminCategoryTreeRow): boolean {
    const siblings = this.siblingRows(row);
    return siblings.findIndex(candidate => candidate.category.id === row.category.id) > 0;
  }

  canMoveDown(row: AdminCategoryTreeRow): boolean {
    const siblings = this.siblingRows(row);
    const index = siblings.findIndex(candidate => candidate.category.id === row.category.id);
    return index >= 0 && index < siblings.length - 1;
  }

  moveRowUp(row: AdminCategoryTreeRow): void {
    const siblings = this.siblingRows(row);
    const index = siblings.findIndex(candidate => candidate.category.id === row.category.id);
    if (index > 0) {
      this.reorder.emit({ id: row.category.id, targetId: siblings[index - 1].category.id });
    }
  }

  moveRowDown(row: AdminCategoryTreeRow): void {
    const siblings = this.siblingRows(row);
    const index = siblings.findIndex(candidate => candidate.category.id === row.category.id);
    if (index >= 0 && index < siblings.length - 1) {
      // Emitted with roles reversed: reorder() always inserts `id` before
      // `targetId`, so moving the *next* sibling in front of this row
      // produces the same adjacent swap as "move this row down".
      this.reorder.emit({ id: siblings[index + 1].category.id, targetId: row.category.id });
    }
  }

  healthItems(category: AdminCategory): CategoryHealthItem[] {
    const health = this.health(category);
    return [
      { labelKey: 'adminCategories.healthImage', done: health.hasImage },
      { labelKey: 'adminCategories.healthSeo', done: health.hasSeo },
      { labelKey: 'adminCategories.healthDescription', done: health.hasDescription },
      { labelKey: 'adminCategories.healthParent', done: health.hasValidParent },
      { labelKey: 'adminCategories.healthVisibility', done: health.isVisible },
      { labelKey: 'adminCategories.healthProducts', done: health.hasProducts },
    ];
  }

  onDragStart(id: string): void {
    this.draggedId = id;
  }

  onDrop(targetRow: AdminCategoryTreeRow): void {
    if (!this.draggedId || this.draggedId === targetRow.category.id) {
      this.draggedId = null;
      return;
    }
    this.reorder.emit({ id: this.draggedId, targetId: targetRow.category.id });
    this.draggedId = null;
  }

  onTreeKeydown(event: KeyboardEvent, row: AdminCategoryTreeRow, index: number): void {
    if (event.key === 'ArrowDown') {
      event.preventDefault();
      this.focusRow(index + 1);
    } else if (event.key === 'ArrowUp') {
      event.preventDefault();
      this.focusRow(index - 1);
    } else if (event.key === 'ArrowRight') {
      event.preventDefault();
      if (row.hasChildren && !this.isExpanded(row.category.id)) {
        this.toggleExpand.emit(row.category.id);
      } else {
        this.focusRow(index + 1);
      }
    } else if (event.key === 'ArrowLeft') {
      event.preventDefault();
      if (row.hasChildren && this.isExpanded(row.category.id)) {
        this.toggleExpand.emit(row.category.id);
      } else if (row.category.parentId) {
        this.jumpToParent.emit(row.category.id);
      }
    } else if (event.key === 'Enter') {
      event.preventDefault();
      this.edit.emit(row.category.id);
    }
  }

  private focusRow(index: number): void {
    const clamped = Math.max(0, Math.min(this.treeRows.length - 1, index));
    this.focusedRowIndex.set(clamped);
    queueMicrotask(() => {
      document.getElementById(`category-tree-row-${this.treeRows[clamped]?.category.id}`)?.focus();
    });
  }

  openAssignParent(): void {
    this.assignParentOpen.set(true);
  }

  confirmAssignParent(parentId: string): void {
    this.bulkAssignParent.emit(parentId || null);
    this.assignParentOpen.set(false);
  }

  openBulkImagePicker(): void {
    this.imagePickerOpen.set(true);
  }

  onBulkImagePicked(asset: MediaAsset): void {
    this.bulkAssignImage.emit(asset.url);
    this.imagePickerOpen.set(false);
  }
}
