import { Injectable, signal, computed } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Region, GeoIpResponse } from '../models/location.model';
import { ApiConfigService } from '../core/config/api-config.service';
import { LocalStorageService } from '../core/storage/local-storage.service';

const STORAGE_KEY = 'selected_region';

@Injectable({
  providedIn: 'root'
})
export class LocationService {
  private regionSignal = signal<Region | null>(null);
  private regionsSignal = signal<Region[]>([]);
  private loadingSignal = signal(false);
  private detectedSignal = signal(false);

  /** Current selected region (null = global / all regions) */
  readonly region = this.regionSignal.asReadonly();
  /** All available regions */
  readonly regions = this.regionsSignal.asReadonly();
  /** Whether geo-detection is in progress */
  readonly detecting = this.loadingSignal.asReadonly();
  /** Whether region was auto-detected */
  readonly autoDetected = this.detectedSignal.asReadonly();

  /** Computed region id for API calls — empty string means global */
  readonly regionId = computed(() => this.regionSignal()?.id ?? '');

  constructor(
    private readonly http: HttpClient,
    private readonly apiConfig: ApiConfigService,
    private readonly storage: LocalStorageService
  ) {
    this.loadRegions();
    this.restoreFromStorage();
  }

  /** Fetch available regions from backend */
  loadRegions(): void {
    this.http.get<Region[]>(`${this.apiConfig.getBaseUrl()}/regions`).subscribe({
      next: (regions) => {
        this.regionsSignal.set(regions);
        // If we have a stored region, validate it still exists
        const stored = this.regionSignal();
        if (stored && !regions.find(r => r.id === stored.id)) {
          this.clearRegion();
        }
      },
      error: () => {
        // Fallback: hardcoded popular regions
        this.regionsSignal.set(this.getFallbackRegions());
      }
    });
  }

  /** Set region by user choice */
  setRegion(region: Region): void {
    this.regionSignal.set(region);
    this.storage.setJSON(STORAGE_KEY, region);
  }

  /** Clear region (go global) */
  clearRegion(): void {
    this.regionSignal.set(null);
    this.storage.removeItem(STORAGE_KEY);
  }

  /** Auto-detect user location via IP geolocation */
  detectLocation(): void {
    if (this.detectedSignal()) return; // already tried
    this.loadingSignal.set(true);

    // Was a direct plaintext call to ip-api.com. Two problems, one of them
    // fatal: browsers block mixed active content, so on an HTTPS storefront
    // this request never completed and auto-detect only ever took the error
    // branch below. It also handed every visitor's IP to a third party from
    // the page itself. The client IP is the server's to read - same tenant
    // API base as /regions, same-origin, nothing leaves our infrastructure.
    this.http.get<GeoIpResponse>(`${this.apiConfig.getBaseUrl()}/geo/resolve`)
      .subscribe({
        next: (geo) => {
          this.detectedSignal.set(true);
          this.loadingSignal.set(false);

          // Only auto-set if user hasn't manually chosen a region
          if (!this.regionSignal()) {
            const matchedRegion = this.findRegionByGeo(geo);
            if (matchedRegion) {
              this.setRegion(matchedRegion);
            }
          }
        },
        error: () => {
          this.detectedSignal.set(true);
          this.loadingSignal.set(false);
        }
      });
  }

  /** Try to match detected geo data to an available region */
  private findRegionByGeo(geo: GeoIpResponse): Region | null {
    const regions = this.regionsSignal();
    if (!regions.length) return null;

    // Exact city match
    const cityMatch = regions.find(r =>
      r.city.toLowerCase() === geo.city?.toLowerCase()
    );
    if (cityMatch) return cityMatch;

    // Country match — pick the first region for that country
    const countryMatch = regions.find(r =>
      r.countryCode.toLowerCase() === geo.countryCode?.toLowerCase()
    );
    return countryMatch || null;
  }

  /** Restore previously selected region from storage */
  private restoreFromStorage(): void {
    const region = this.storage.getJSON<Region>(STORAGE_KEY);
    if (region) {
      this.regionSignal.set(region);
    }
  }

  /** Fallback regions if backend /regions endpoint is unavailable */
  private getFallbackRegions(): Region[] {
    return [
      { id: 'moscow', city: 'Москва', country: 'Россия', countryCode: 'RU', timezone: 'Europe/Moscow' },
      { id: 'spb', city: 'Санкт-Петербург', country: 'Россия', countryCode: 'RU', timezone: 'Europe/Moscow' },
      { id: 'yerevan', city: 'Ереван', country: 'Армения', countryCode: 'AM', timezone: 'Asia/Yerevan' },
      { id: 'minsk', city: 'Минск', country: 'Беларусь', countryCode: 'BY', timezone: 'Europe/Minsk' },
      { id: 'almaty', city: 'Алматы', country: 'Казахстан', countryCode: 'KZ', timezone: 'Asia/Almaty' },
      { id: 'tbilisi', city: 'Тбилиси', country: 'Грузия', countryCode: 'GE', timezone: 'Asia/Tbilisi' },
    ];
  }
}
