import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ProjectEditorFacade } from '../../project-editor/facade/project-editor.facade';
import { ContentManagementFacade } from '../facade/content-management.facade';
import { ContentPage, ContentPageSeoConfig, ContentPageStatus } from '../models/content-page.model';
import { findLegalDefinition } from '../models/legal-pages.model';
import { BootstrapConfig } from '../../../shared/models/config';
import { TranslatePipe } from '../../../i18n/translate.pipe';
import { TranslateService } from '../../../i18n/translate.service';
import { ButtonComponent } from '../../../shared/ui/button/button.component';
import { InputComponent } from '../../../shared/ui/input/input.component';
import { FormFieldComponent } from '../../../shared/ui/form-field/form-field.component';
import { EmptyStateComponent } from '../../../shared/ui/empty-state/empty-state.component';
import { SectionCardComponent } from '../../../shared/ui/section-card/section-card.component';
import { SelectComponent, SelectOption } from '../../../shared/ui/select/select.component';
import { ToggleComponent } from '../../../shared/ui/toggle/toggle.component';
import { MediaPickerComponent } from '../../../shared/media/media-picker/media-picker.component';
import { MediaAsset } from '../../../core/media/models/media-asset.model';
import { StaticPagePreviewComponent } from './static-page-preview/static-page-preview.component';
import { ContentDashboardComponent } from './content-dashboard/content-dashboard.component';
import { PageCardComponent, PageSeoStatus } from './page-card/page-card.component';
import { PageEditorComponent, PageMediaField } from './page-editor/page-editor.component';
import { ConfirmDialogComponent } from '../../../shared/ui/confirm-dialog/confirm-dialog.component';

type StatusFilter = 'all' | ContentPageStatus;
const ALL_LOCALES_FILTER = 'all';

@Component({
  selector: 'app-static-pages-editor',
  standalone: true,
  imports: [
    FormsModule,
    TranslatePipe,
    ButtonComponent,
    InputComponent,
    FormFieldComponent,
    EmptyStateComponent,
    SectionCardComponent,
    SelectComponent,
    ToggleComponent,
    MediaPickerComponent,
    StaticPagePreviewComponent,
    ContentDashboardComponent,
    PageCardComponent,
    PageEditorComponent,
    ConfirmDialogComponent,
  ],
  templateUrl: './static-pages-editor.component.html',
  styleUrls: ['../../project-editor/sections/section.shared.scss', './static-pages-editor.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class StaticPagesEditorComponent {
  private readonly projectEditor = inject(ProjectEditorFacade);
  private readonly contentFacade = inject(ContentManagementFacade);
  private readonly translate = inject(TranslateService);

  readonly bootstrap = this.projectEditor.bootstrap;
  readonly fieldError = (key: string): string | null => {
    const messageKey = this.projectEditor.fieldError(key);
    return messageKey ? this.translate.t(messageKey) : null;
  };
  readonly allPages = computed(() => this.contentFacade.pages(this.bootstrap()));
  readonly validation = computed(() => this.contentFacade.validatePages(this.bootstrap()));
  readonly contentHealth = computed(() => this.contentFacade.contentHealth(this.bootstrap()));
  readonly locales = computed(() => this.bootstrap()?.localization.supportedLocales ?? ['en']);
  readonly defaultLocale = computed(() => this.bootstrap()?.localization.defaultLocale ?? 'en');

  readonly searchQuery = signal('');
  readonly statusFilter = signal<StatusFilter>('all');
  readonly localeFilter = signal<string>(ALL_LOCALES_FILTER);
  readonly selectedIds = signal<Set<string>>(new Set());
  readonly editingPageId = signal<string | null>(null);
  readonly previewOpenPageId = signal<string | null>(null);

  readonly editingPage = computed(() => this.allPages().find(page => page.id === this.editingPageId()) ?? null);

  readonly statusFilterOptions = computed<SelectOption[]>(() => [
    { value: 'all', label: this.translate.t('staticPages.filterAll') },
    { value: 'draft', label: this.translate.t('builder.statusDraft') },
    { value: 'published', label: this.translate.t('builder.statusPublished') },
  ]);

  readonly localeFilterOptions = computed<SelectOption[]>(() => [
    { value: ALL_LOCALES_FILTER, label: this.translate.t('staticPages.filterAllLocales') },
    ...this.locales().map(locale => ({ value: locale, label: locale })),
  ]);

  readonly pages = computed(() => {
    const query = this.searchQuery().trim().toLowerCase();
    const status = this.statusFilter();
    const locale = this.localeFilter();

    const filtered = this.allPages().filter(page => {
      if (status !== 'all' && page.status !== status) {
        return false;
      }
      if (locale !== ALL_LOCALES_FILTER && !(page.translations[locale]?.title ?? '').trim()) {
        return false;
      }
      if (!query) {
        return true;
      }
      const haystack = [page.id, page.slug, page.route, page.title, ...Object.values(page.translations).map(t => t.title ?? '')]
        .join(' ')
        .toLowerCase();
      return haystack.includes(query);
    });

    // Legal pages surface first (Task 3) - stable sort keeps the rest in their existing order.
    return [...filtered].sort((a, b) => {
      const aLegal = findLegalDefinition(a) ? 0 : 1;
      const bLegal = findLegalDefinition(b) ? 0 : 1;
      return aLegal - bLegal;
    });
  });

  readonly selectedCount = computed(() => this.selectedIds().size);
  readonly allVisibleSelected = computed(() => {
    const visible = this.pages();
    return visible.length > 0 && visible.every(page => this.selectedIds().has(page.id));
  });

  private readonly originalPagesById = computed<Map<string, ContentPage>>(() => {
    const staticPages = this.projectEditor.originalStaticPages();
    if (!staticPages) {
      return new Map();
    }
    const normalized = this.contentFacade.pages({ staticPages } as BootstrapConfig);
    return new Map(normalized.map(page => [page.id, page]));
  });

  isModified(page: ContentPage): boolean {
    const original = this.originalPagesById().get(page.id);
    if (!original) {
      return true;
    }
    return JSON.stringify(page) !== JSON.stringify(original);
  }

  legalLabelKey(page: ContentPage): string | null {
    return findLegalDefinition(page)?.labelKey ?? null;
  }

  seoStatus(page: ContentPage): PageSeoStatus {
    if (this.hasInvalidSeo(page)) {
      return 'warning';
    }
    const hasSeo = this.contentFacade.hasSeoContent(page);
    if (!hasSeo) {
      return 'missing';
    }
    const complete = !!(page.seo?.title?.trim() && page.seo?.description?.trim());
    return complete ? 'good' : 'partial';
  }

  hasAnyIssue(page: ContentPage): boolean {
    return this.hasDuplicateSlug(page) || this.hasDuplicateRoute(page) || this.hasEmptyTitle(page) || this.hasInvalidHtml(page);
  }

  updatedAtLabel(page: ContentPage): string | null {
    return page.updatedAt ? new Date(page.updatedAt).toLocaleDateString() : null;
  }

  openEditor(id: string): void {
    this.editingPageId.set(id);
  }

  closeEditor(): void {
    this.editingPageId.set(null);
  }

  togglePreview(pageId: string): void {
    this.previewOpenPageId.set(this.previewOpenPageId() === pageId ? null : pageId);
  }

  previewHtml(page: ContentPage): string {
    const defaultLocale = this.defaultLocale();
    return page.translations[defaultLocale]?.html ?? Object.values(page.translations)[0]?.html ?? '';
  }

  previewTitle(page: ContentPage): string {
    const defaultLocale = this.defaultLocale();
    return page.translations[defaultLocale]?.title || page.title;
  }

  protected mediaPickerOpen = false;
  private mediaPickerTarget: { pageId: string; field: PageMediaField } | null = null;

  openMediaPicker(pageId: string, field: PageMediaField): void {
    this.mediaPickerTarget = { pageId, field };
    this.mediaPickerOpen = true;
  }

  onImagePicked(asset: MediaAsset): void {
    if (this.mediaPickerTarget) {
      this.updatePage(this.mediaPickerTarget.pageId, { [this.mediaPickerTarget.field]: asset.url });
    }
    this.mediaPickerOpen = false;
  }

  clearMedia(pageId: string, field: PageMediaField): void {
    this.updatePage(pageId, { [field]: undefined });
  }

  private uniqueValue(candidate: string, existing: Set<string>): string {
    if (!existing.has(candidate)) {
      return candidate;
    }
    let suffix = 2;
    while (existing.has(`${candidate}-${suffix}`)) {
      suffix++;
    }
    return `${candidate}-${suffix}`;
  }

  createPage(): void {
    const existingSlugs = new Set(this.allPages().map(page => page.slug));
    const slug = this.uniqueValue(`custom-page-${this.allPages().length + 1}`, existingSlugs);
    const page: ContentPage = {
      id: `page-${Date.now()}`,
      slug,
      route: slug,
      title: '',
      order: this.allPages().length + 1,
      showInFooter: false,
      showInHeader: false,
      showInSitemap: true,
      visibility: { desktop: true, tablet: true, mobile: true },
      requiresAuthentication: false,
      translations: {
        en: { title: '', html: '' },
        ru: { title: '', html: '' },
        hy: { title: '', html: '' },
      },
      enabled: true,
      status: 'draft',
      updatedAt: new Date().toISOString(),
    };

    this.persist([...this.allPages(), page]);
    this.openEditor(page.id);
  }

  duplicatePage(id: string): void {
    const source = this.allPages().find(page => page.id === id);
    if (!source) {
      return;
    }
    const existingSlugs = new Set(this.allPages().map(page => page.slug));
    const existingRoutes = new Set(this.allPages().map(page => page.route));
    const clone: ContentPage = {
      ...source,
      id: `page-${Date.now()}`,
      slug: this.uniqueValue(`${source.slug}-copy`, existingSlugs),
      route: this.uniqueValue(`${source.route}-copy`, existingRoutes),
      order: this.allPages().length + 1,
      status: 'draft',
      translations: Object.fromEntries(Object.entries(source.translations).map(([locale, t]) => [locale, { ...t }])),
      updatedAt: new Date().toISOString(),
    };
    this.persist([...this.allPages(), clone]);
  }

  readonly pendingDeletePageId = signal<string | null>(null);

  deletePage(id: string): void {
    this.pendingDeletePageId.set(id);
  }

  confirmDeletePage(): void {
    const id = this.pendingDeletePageId();
    this.pendingDeletePageId.set(null);
    if (!id) return;
    this.persist(this.allPages().filter(page => page.id !== id));
    this.deselect(id);
    if (this.editingPageId() === id) {
      this.closeEditor();
    }
  }

  updatePage(id: string, patch: Partial<ContentPage>): void {
    this.persist(this.allPages().map(page => page.id !== id ? page : ({ ...page, ...patch, updatedAt: new Date().toISOString() })));
  }

  updateTranslation(id: string, locale: string, field: 'title' | 'html', value: string): void {
    this.persist(this.allPages().map(page => page.id !== id ? page : ({
      ...page,
      updatedAt: new Date().toISOString(),
      translations: {
        ...page.translations,
        [locale]: {
          ...(page.translations[locale] ?? {}),
          [field]: value,
        }
      }
    })));
  }

  hasDuplicateSlug(page: ContentPage): boolean {
    return this.validation().duplicateSlugs.includes(this.contentFacade.normalizeSlug(page.slug));
  }

  hasEmptyTitle(page: ContentPage): boolean {
    return this.validation().emptyTitles.includes(page.id);
  }

  hasDuplicateRoute(page: ContentPage): boolean {
    return this.validation().duplicateRoutes.includes(page.route || page.slug);
  }

  hasInvalidHtml(page: ContentPage): boolean {
    return this.validation().invalidHtml.includes(page.id);
  }

  hasInvalidSeo(page: ContentPage): boolean {
    return this.validation().invalidSeo.includes(page.id);
  }

  updateGallery(id: string, value: string): void {
    const gallery = value.split(',').map(url => url.trim()).filter(url => url.length > 0);
    this.updatePage(id, { gallery });
  }

  updateSeo(id: string, patch: Partial<ContentPageSeoConfig>): void {
    this.persist(this.allPages().map(page => page.id !== id ? page : ({
      ...page,
      updatedAt: new Date().toISOString(),
      seo: {
        ...(page.seo ?? {}),
        ...patch,
      }
    })));
  }

  move(id: string, direction: -1 | 1): void {
    const pages = [...this.allPages()].sort((a, b) => a.order - b.order);
    const index = pages.findIndex(page => page.id === id);
    const nextIndex = index + direction;
    if (index < 0 || nextIndex < 0 || nextIndex >= pages.length) {
      return;
    }

    const current = pages[index];
    pages[index] = pages[nextIndex];
    pages[nextIndex] = current;
    this.persist(pages.map((page, order) => ({ ...page, order: order + 1 })));
  }

  updateSearchQuery(value: string): void {
    this.searchQuery.set(value);
  }

  updateStatusFilter(value: string): void {
    this.statusFilter.set(value as StatusFilter);
  }

  updateLocaleFilter(value: string): void {
    this.localeFilter.set(value);
  }

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

  toggleSelect(id: string, checked: boolean): void {
    const next = new Set(this.selectedIds());
    checked ? next.add(id) : next.delete(id);
    this.selectedIds.set(next);
  }

  toggleSelectAllVisible(checked: boolean): void {
    const next = new Set(this.selectedIds());
    for (const page of this.pages()) {
      checked ? next.add(page.id) : next.delete(page.id);
    }
    this.selectedIds.set(next);
  }

  private deselect(id: string): void {
    const next = new Set(this.selectedIds());
    next.delete(id);
    this.selectedIds.set(next);
  }

  clearSelection(): void {
    this.selectedIds.set(new Set());
  }

  readonly bulkDeleteConfirmOpen = signal(false);

  bulkDelete(): void {
    this.bulkDeleteConfirmOpen.set(true);
  }

  confirmBulkDelete(): void {
    this.bulkDeleteConfirmOpen.set(false);
    const ids = this.selectedIds();
    this.persist(this.allPages().filter(page => !ids.has(page.id)));
    this.clearSelection();
  }

  bulkSetEnabled(enabled: boolean): void {
    const ids = this.selectedIds();
    this.persist(this.allPages().map(page => ids.has(page.id) ? { ...page, enabled } : page));
  }

  bulkSetStatus(status: ContentPageStatus): void {
    const ids = this.selectedIds();
    this.persist(this.allPages().map(page => ids.has(page.id) ? { ...page, status } : page));
  }

  private persist(pages: ContentPage[]): void {
    this.projectEditor.updateBootstrap(current => ({
      ...current,
      staticPages: this.contentFacade.serializePages(pages)
    }));
  }
}
