import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ProjectEditorFacade } from '../facade/project-editor.facade';
import { TranslatePipe } from '../../../i18n/translate.pipe';
import { TranslateService } from '../../../i18n/translate.service';
import { InputComponent } from '../../../shared/ui/input/input.component';
import { ButtonComponent } from '../../../shared/ui/button/button.component';
import { SectionCardComponent } from '../../../shared/ui/section-card/section-card.component';
import { ToggleComponent } from '../../../shared/ui/toggle/toggle.component';
import { EmptyStateComponent } from '../../../shared/ui/empty-state/empty-state.component';
import { WidgetConfig } from '../../../shared/models/config';
import { IconComponent } from '../../../shared/ui/icon/icon.component';
import { AppIconName } from '../../../shared/ui/icon/icon-registry';
import { ConfirmDialogComponent } from '../../../shared/ui/confirm-dialog/confirm-dialog.component';

interface HeroSlideDraft {
  title: string;
  subtitle: string;
}

const WIDGET_ICONS: Record<string, AppIconName> = {
  hero: 'image',
  categories: 'layoutGrid',
  'product-collection': 'package',
};

const WIDGET_LABEL_KEYS: Record<string, string> = {
  hero: 'builder.widgetTypeHero',
  categories: 'builder.widgetTypeCategories',
  'product-collection': 'builder.widgetTypeProducts',
};

@Component({
  selector: 'app-project-editor-widgets-section',
  standalone: true,
  imports: [FormsModule, TranslatePipe, InputComponent, ButtonComponent, SectionCardComponent, ToggleComponent, EmptyStateComponent, IconComponent, ConfirmDialogComponent],
  templateUrl: './widgets-section.component.html',
  styleUrls: ['./section.shared.scss', './widgets-section.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ProjectEditorWidgetsSectionComponent {
  private readonly facade = inject(ProjectEditorFacade);
  private readonly translate = inject(TranslateService);
  readonly widgets = this.facade.homepageWidgets;
  readonly fieldError = (key: string): string | null => {
    const messageKey = this.facade.fieldError(key);
    return messageKey ? this.translate.t(messageKey) : null;
  };

  widgetIcon(type: string): AppIconName {
    return WIDGET_ICONS[type] ?? 'stop';
  }

  widgetLabel(widget: WidgetConfig): string {
    if (widget.title) {
      return widget.title;
    }
    const key = WIDGET_LABEL_KEYS[widget.type];
    return key ? this.translate.t(key) : widget.type;
  }

  isVisible(widget: WidgetConfig): boolean {
    return widget.visible !== false;
  }

  toggleVisible(widgetId: string): void {
    this.updateWidgetConfig(widgetId, widget => ({ ...widget, visible: !this.isVisible(widget) }));
  }

  moveWidget(widgetId: string, direction: -1 | 1): void {
    this.facade.updateBootstrap(current => ({
      ...current,
      pages: current.pages.map(page => ({
        ...page,
        sections: page.sections.map(section => {
          const index = section.widgets.findIndex(w => w.id === widgetId);
          if (index === -1) {
            return section;
          }
          const targetIndex = index + direction;
          if (targetIndex < 0 || targetIndex >= section.widgets.length) {
            return section;
          }
          const widgets = [...section.widgets];
          [widgets[index], widgets[targetIndex]] = [widgets[targetIndex], widgets[index]];
          return { ...section, widgets };
        })
      }))
    }));
  }

  duplicateWidget(widgetId: string): void {
    this.facade.updateBootstrap(current => ({
      ...current,
      pages: current.pages.map(page => ({
        ...page,
        sections: page.sections.map(section => {
          const index = section.widgets.findIndex(w => w.id === widgetId);
          if (index === -1) {
            return section;
          }
          const original = section.widgets[index];
          const copy: WidgetConfig = { ...original, id: `${original.id}-copy-${Date.now()}` };
          const widgets = [...section.widgets];
          widgets.splice(index + 1, 0, copy);
          return { ...section, widgets };
        })
      }))
    }));
  }

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

  removeWidget(widgetId: string): void {
    this.pendingRemoveWidgetId.set(widgetId);
  }

  confirmRemoveWidget(): void {
    const widgetId = this.pendingRemoveWidgetId();
    this.pendingRemoveWidgetId.set(null);
    if (!widgetId) return;
    this.facade.updateBootstrap(current => ({
      ...current,
      pages: current.pages.map(page => ({
        ...page,
        sections: page.sections.map(section => ({
          ...section,
          widgets: section.widgets.filter(w => w.id !== widgetId)
        }))
      }))
    }));
  }

  private updateWidgetConfig(widgetId: string, updater: (widget: WidgetConfig) => WidgetConfig): void {
    this.facade.updateBootstrap(current => ({
      ...current,
      pages: current.pages.map(page => ({
        ...page,
        sections: page.sections.map(section => ({
          ...section,
          widgets: section.widgets.map(widget => widget.id !== widgetId ? widget : updater(widget))
        }))
      }))
    }));
  }

  updateWidget(widgetId: string, updater: (props: Record<string, unknown>) => Record<string, unknown>): void {
    this.updateWidgetConfig(widgetId, widget => ({ ...widget, props: updater(widget.props ?? {}) }));
  }

  updateProp(widgetId: string, key: string, value: unknown): void {
    this.updateWidget(widgetId, props => ({ ...props, [key]: value }));
  }

  /** Extra slides beyond the widget's primary title/subtitle (which stay editable as "slide 1" via the existing fields above this list). */
  heroSlides(widget: WidgetConfig): HeroSlideDraft[] {
    const raw = widget.props?.['slides'];
    if (!Array.isArray(raw)) {
      return [];
    }
    return raw.map(slide => ({
      title: typeof slide?.title === 'string' ? slide.title : '',
      subtitle: typeof slide?.subtitle === 'string' ? slide.subtitle : '',
    }));
  }

  addHeroSlide(widgetId: string): void {
    this.updateWidget(widgetId, props => ({
      ...props,
      slides: [...this.slidesArray(props), { title: '', subtitle: '' }],
    }));
  }

  updateHeroSlide(widgetId: string, index: number, field: 'title' | 'subtitle', value: string): void {
    this.updateWidget(widgetId, props => ({
      ...props,
      slides: this.slidesArray(props).map((slide, i) => i === index ? { ...slide, [field]: value } : slide),
    }));
  }

  removeHeroSlide(widgetId: string, index: number): void {
    this.updateWidget(widgetId, props => ({
      ...props,
      slides: this.slidesArray(props).filter((_, i) => i !== index),
    }));
  }

  private slidesArray(props: Record<string, unknown>): HeroSlideDraft[] {
    const raw = props['slides'];
    return Array.isArray(raw) ? raw : [];
  }

  private readonly jsonDrafts = signal<Record<string, string>>({});
  private readonly jsonErrors = signal<Record<string, string>>({});

  /**
   * While the textarea holds invalid JSON, keep showing the user's own draft
   * (not the last-committed props) so their in-progress edit isn't silently
   * overwritten on the next change-detection pass.
   */
  widgetJsonValue(widgetId: string, props: Record<string, unknown>): string {
    return this.jsonDrafts()[widgetId] ?? this.propsJson(props);
  }

  widgetJsonError(widgetId: string): string | null {
    return this.jsonErrors()[widgetId] ?? null;
  }

  updateJson(widgetId: string, raw: string): void {
    try {
      const parsed = JSON.parse(raw);
      this.updateWidget(widgetId, () => parsed);
      this.jsonDrafts.update(({ [widgetId]: _removed, ...rest }) => rest);
      this.jsonErrors.update(({ [widgetId]: _removed, ...rest }) => rest);
    } catch {
      this.jsonDrafts.update(drafts => ({ ...drafts, [widgetId]: raw }));
      this.jsonErrors.update(errors => ({ ...errors, [widgetId]: this.translate.t('builder.widgetJsonInvalid') }));
    }
  }

  propsJson(props: Record<string, unknown>): string {
    return JSON.stringify(props ?? {}, null, 2);
  }
}
