import { Injectable, inject, computed, signal } from '@angular/core';
import { Store } from '@ngrx/store';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { selectUser } from '../store/auth/auth.reducer';
import { environment } from '../../../environments/environment';

@Injectable({ providedIn: 'root' })
export class PermissionService {
  private store = inject(Store);
  private http = inject(HttpClient);
  private currentUser = this.store.selectSignal(selectUser);
  private settingsUrl = `${environment.apiUrl}/core/settings`;

  /** Hidden routes per role loaded from settings */
  hiddenRoutesSet = signal<Set<string>>(new Set());
  private navConfigLoaded = signal(false);

  /** Super admin = empty roles & permissions, or user not yet loaded */
  isSuperAdmin = computed(() => {
    const user = this.currentUser();
    if (!user) return true; // Not loaded yet — allow all to avoid flash
    return user.roles.length === 0 && user.permissions.length === 0;
  });

  /** Check if user has any permission starting with at least one prefix */
  hasAnyPermission(prefixes: string[]): boolean {
    if (this.isSuperAdmin()) return true;
    const userPerms = this.currentUser()?.permissions || [];
    return prefixes.some(prefix => userPerms.some(p => p.startsWith(prefix)));
  }

  /** Check a single permission prefix */
  hasPermission(prefix: string): boolean {
    return this.hasAnyPermission([prefix]);
  }

  /** Check if a route is hidden by role nav customization */
  isRouteHidden(route: string): boolean {
    if (this.isSuperAdmin()) return false;
    return this.hiddenRoutesSet().has(route);
  }

  /** Load nav customization for the current user's roles */
  loadNavConfig(): void {
    const user = this.currentUser();
    if (!user || this.navConfigLoaded()) return;
    if (this.isSuperAdmin()) { this.navConfigLoaded.set(true); return; }

    const roles = user.roles || [];
    if (!roles.length) { this.navConfigLoaded.set(true); return; }

    let loadedCount = 0;
    const allHidden = new Set<string>();
    for (const roleName of roles) {
      const key = `roles.${roleName}.nav_config`;
      this.http.get<any>(`${this.settingsUrl}/${key}`).subscribe({
        next: (res) => {
          try {
            const val = res?.data?.value ?? res?.value;
            const config = typeof val === 'string' ? JSON.parse(val) : val;
            if (config?.hiddenRoutes && Array.isArray(config.hiddenRoutes)) {
              config.hiddenRoutes.forEach((r: string) => allHidden.add(r));
            }
          } catch {}
          loadedCount++;
          if (loadedCount === roles.length) {
            this.hiddenRoutesSet.set(allHidden);
            this.navConfigLoaded.set(true);
          }
        },
        error: () => {
          loadedCount++;
          if (loadedCount === roles.length) {
            this.hiddenRoutesSet.set(allHidden);
            this.navConfigLoaded.set(true);
          }
        },
      });
    }
  }

  /** Save nav config for a role */
  saveNavConfig(roleName: string, hiddenRoutes: string[]): Observable<any> {
    return this.http.put(this.settingsUrl, {
      setting_key: `roles.${roleName}.nav_config`,
      value: JSON.stringify({ hiddenRoutes }),
    });
  }

  /** Get nav config for a specific role */
  getNavConfig(roleName: string): Observable<string[]> {
    const key = `roles.${roleName}.nav_config`;
    return new Observable<string[]>((subscriber) => {
      this.http.get<any>(`${this.settingsUrl}/${key}`).subscribe({
        next: (res) => {
          try {
            const val = res?.data?.value ?? res?.value;
            const config = typeof val === 'string' ? JSON.parse(val) : val;
            subscriber.next(config?.hiddenRoutes || []);
          } catch {
            subscriber.next([]);
          }
          subscriber.complete();
        },
        error: () => {
          subscriber.next([]);
          subscriber.complete();
        },
      });
    });
  }
}
