import { Injectable } from '@angular/core';
import { BootstrapConfig, FooterNavigationGroupConfig, NavigationItemConfig, NavigationLocalizedText } from '../../../shared/models/config';

type SyncMode = 'add' | 'remove';

@Injectable({ providedIn: 'root' })
export class LocaleSyncService {
  addLocale(bootstrap: BootstrapConfig, locale: string): BootstrapConfig {
    return this.sync(bootstrap, locale, 'add');
  }

  removeLocale(bootstrap: BootstrapConfig, locale: string): BootstrapConfig {
    if (locale === bootstrap.localization.defaultLocale) {
      return bootstrap;
    }
    return this.sync(bootstrap, locale, 'remove');
  }

  private sync(bootstrap: BootstrapConfig, rawLocale: string, mode: SyncMode): BootstrapConfig {
    const locale = rawLocale.trim().toLowerCase();
    if (!locale) {
      return bootstrap;
    }

    const alreadyPresent = bootstrap.localization.supportedLocales.includes(locale);
    if (mode === 'add' && alreadyPresent) {
      return bootstrap;
    }
    if (mode === 'remove' && !alreadyPresent) {
      return bootstrap;
    }

    const supportedLocales = mode === 'add'
      ? [...bootstrap.localization.supportedLocales, locale]
      : bootstrap.localization.supportedLocales.filter(existing => existing !== locale);

    return {
      ...bootstrap,
      tenant: { ...bootstrap.tenant, supportedLocales },
      localization: { ...bootstrap.localization, supportedLocales },
      staticPages: this.syncStaticPages(bootstrap.staticPages, locale, mode),
      navigation: {
        ...bootstrap.navigation,
        header: this.syncNavItems(bootstrap.navigation.header, locale, mode),
        footer: this.syncFooterNav(bootstrap.navigation.footer, locale, mode),
        sidebar: bootstrap.navigation.sidebar ? this.syncNavItems(bootstrap.navigation.sidebar, locale, mode) : bootstrap.navigation.sidebar,
      },
    };
  }

  private syncStaticPages(staticPages: BootstrapConfig['staticPages'], locale: string, mode: SyncMode): BootstrapConfig['staticPages'] {
    if (!staticPages || Array.isArray(staticPages)) {
      return staticPages;
    }

    return Object.fromEntries(
      Object.entries(staticPages).map(([id, page]) => [id, {
        ...page,
        translations: this.syncRecord(page.translations, locale, mode, () => ({ title: '', html: '' })),
      }])
    );
  }

  private syncNavItems(items: NavigationItemConfig[], locale: string, mode: SyncMode): NavigationItemConfig[] {
    return items.map(item => ({
      ...item,
      label: this.syncLabel(item.label, locale, mode),
      children: item.children ? this.syncNavItems(item.children, locale, mode) : item.children,
    }));
  }

  private syncFooterNav(
    footer: NavigationItemConfig[] | FooterNavigationGroupConfig[],
    locale: string,
    mode: SyncMode
  ): NavigationItemConfig[] | FooterNavigationGroupConfig[] {
    if (footer.length === 0) {
      return footer;
    }

    if ('items' in footer[0]) {
      return (footer as FooterNavigationGroupConfig[]).map(group => ({
        ...group,
        groupTitle: this.syncLabel(group.groupTitle, locale, mode),
        items: group.items.map(item => ({ ...item, label: this.syncLabel(item.label, locale, mode) })),
      }));
    }

    return this.syncNavItems(footer as NavigationItemConfig[], locale, mode);
  }

  private syncLabel(
    label: string | NavigationLocalizedText | undefined,
    locale: string,
    mode: SyncMode
  ): string | NavigationLocalizedText | undefined {
    if (label === undefined || typeof label === 'string') {
      return label;
    }
    return this.syncRecord(label, locale, mode, () => Object.values(label)[0] ?? '');
  }

  private syncRecord<T>(
    record: Record<string, T> | undefined,
    locale: string,
    mode: SyncMode,
    createEmpty: () => T
  ): Record<string, T> {
    const next: Record<string, T> = { ...(record ?? {}) };
    if (mode === 'add') {
      if (!(locale in next)) {
        next[locale] = createEmpty();
      }
    } else {
      delete next[locale];
    }
    return next;
  }
}
