import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators';
import { BackofficeDataService } from '../../../../core/backoffice/backoffice-data.service';
import { CategoryCardConfig } from '../../../../shared/models/ui';
import { AdminCategory, AdminCategoryListFilters } from '../models/admin-category.model';
import { AdminCategoriesGateway } from './admin-categories-gateway.interface';

@Injectable({ providedIn: 'root' })
export class AdminCategoriesLocalGateway implements AdminCategoriesGateway {
  private cache: AdminCategory[] | null = null;

  constructor(private readonly backofficeData: BackofficeDataService) {}

  loadCategories(filters: AdminCategoryListFilters): Observable<AdminCategory[]> {
    return new Observable<AdminCategory[]>(subscriber => {
      this.ensureData().then(() => {
        const filtered = (this.cache ?? [])
          .filter(category => filters.includeDeleted || !category.deletedAt)
          .filter(category => !filters.search || category.title.toLowerCase().includes(filters.search.toLowerCase()))
          .filter(category => filters.visibility === 'all' || (filters.visibility === 'visible' ? category.visible : !category.visible))
          .sort((left, right) => left.order - right.order);
        subscriber.next(filtered);
        subscriber.complete();
      });
    }).pipe(delay(50));
  }

  loadCategory(id: string): Observable<AdminCategory | null> {
    return new Observable<AdminCategory | null>(subscriber => {
      this.ensureData().then(() => {
        subscriber.next(this.cache?.find(category => category.id === id) ?? null);
        subscriber.complete();
      });
    });
  }

  createCategory(category: AdminCategory): Observable<AdminCategory> {
    this.cache = [category, ...(this.cache ?? [])];
    return of(category).pipe(delay(50));
  }

  updateCategory(category: AdminCategory): Observable<AdminCategory> {
    this.cache = (this.cache ?? []).map(item => item.id === category.id ? category : item);
    return of(category).pipe(delay(50));
  }

  deleteCategory(id: string): Observable<void> {
    this.cache = (this.cache ?? []).map(item => item.id === id ? { ...item, deletedAt: new Date().toISOString() } : item);
    return of(void 0).pipe(delay(50));
  }

  restoreCategory(id: string): Observable<AdminCategory | null> {
    const restored = (this.cache ?? []).find(item => item.id === id);
    if (!restored) {
      return of(null);
    }
    const updated = { ...restored, deletedAt: null, updatedAt: new Date().toISOString() };
    this.cache = (this.cache ?? []).map(item => item.id === id ? updated : item);
    return of(updated).pipe(delay(50));
  }

  isSlugTaken(slug: string, excludingId: string | null): Observable<boolean> {
    return new Observable<boolean>(subscriber => {
      this.ensureData().then(() => {
        const taken = (this.cache ?? []).some(category => category.slug === slug && category.id !== excludingId && !category.deletedAt);
        subscriber.next(taken);
        subscriber.complete();
      });
    });
  }

  hasChildren(id: string): boolean {
    return (this.cache ?? []).some(category => category.parentId === id && !category.deletedAt);
  }

  private async ensureData(): Promise<void> {
    if (this.cache) {
      return;
    }

    // Empty list on transport failure - never leave the promise unsettled.
    const categories = await new Promise<CategoryCardConfig[]>(resolve =>
      this.backofficeData.loadCategories().subscribe({ next: value => resolve(value), error: () => resolve([]) })
    );
    this.cache = categories.map(category => this.toAdminCategory(category));
  }

  private toAdminCategory(category: CategoryCardConfig): AdminCategory {
    const slug = category.title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
    return {
      id: category.id,
      parentId: null,
      title: category.title,
      slug,
      description: category.description ?? '',
      icon: category.icon ?? '',
      imageUrl: category.imageUrl ?? '',
      imageAlt: '',
      order: 0,
      visible: true,
      status: 'published',
      itemsCount: category.itemsCount ?? 0,
      translations: {
        en: { title: category.title, description: category.description ?? '' },
        ru: {},
        hy: {},
      },
      seo: {
        metaTitle: category.title,
        metaDescription: category.description ?? '',
        keywords: '',
      },
      attributes: [],
      deletedAt: null,
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString(),
    };
  }
}
