import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { map, Observable } from 'rxjs';
import {
  InvimaCatalogResponse,
  InvimaCategory,
  InvimaDataset,
  InvimaFiltersResponse,
  InvimaSyncJob,
  InvimaSyncStats,
  InvimaSyncResponse
} from '../models';

export type CatalogQuery = {
  q?: string;
  categorias?: string[];
  datasets?: string[];
  estados?: string[];
  modalidades?: string[];
  grupos?: string[];
  fechaVencDesde?: string;
  fechaVencHasta?: string;
  fechaExpDesde?: string;
  fechaExpHasta?: string;
  onlyVigentes?: boolean;
  limit?: number;
  offset?: number;
};

export type InvimaExportFile = {
  blob: Blob;
  filename: string;
  contentType: string;
};

@Injectable({ providedIn: 'root' })
export class InvimaService {
  private readonly apiBase = '/api/invima';

  constructor(private readonly http: HttpClient) {}

  private buildExportParams(query: CatalogQuery, format: 'csv' | 'xlsx'): HttpParams {
    let params = new HttpParams().set('format', format);

    if (query.q) params = params.set('q', query.q);
    if (query.categorias?.length) params = params.set('categorias', query.categorias.join(','));
    if (query.datasets?.length) params = params.set('datasets', query.datasets.join(','));
    if (query.estados?.length) params = params.set('estados', query.estados.join(','));
    if (query.modalidades?.length) params = params.set('modalidades', query.modalidades.join(','));
    if (query.grupos?.length) params = params.set('grupos', query.grupos.join(','));
    if (query.fechaVencDesde) params = params.set('fechaVencDesde', query.fechaVencDesde);
    if (query.fechaVencHasta) params = params.set('fechaVencHasta', query.fechaVencHasta);
    if (query.fechaExpDesde) params = params.set('fechaExpDesde', query.fechaExpDesde);
    if (query.fechaExpHasta) params = params.set('fechaExpHasta', query.fechaExpHasta);
    if (query.onlyVigentes) params = params.set('onlyVigentes', 'true');

    const exportLimit = format === 'csv' ? '1000000' : '200000';
    return params.set('exportLimit', exportLimit);
  }

  private buildFallbackFilename(format: 'csv' | 'xlsx') {
    const stamp = new Date().toISOString().replace(/[:.]/g, '-');
    return `invima_catalogo_${stamp}.${format}`;
  }

  private extractFilename(contentDisposition: string | null, fallback: string) {
    if (!contentDisposition) return fallback;

    const utf8Match = contentDisposition.match(/filename\*=UTF-8''([^;]+)/i);
    if (utf8Match?.[1]) {
      const decoded = decodeURIComponent(utf8Match[1].trim().replace(/^["']|["']$/g, ''));
      return decoded || fallback;
    }

    const simpleMatch = contentDisposition.match(/filename="?([^";]+)"?/i);
    if (simpleMatch?.[1]) {
      return simpleMatch[1].trim();
    }

    return fallback;
  }

  getDatasets(): Observable<{ items: InvimaDataset[] }> {
    return this.http.get<{ items: InvimaDataset[] }>(`${this.apiBase}/datasets`);
  }

  getCategories(): Observable<{ items: InvimaCategory[] }> {
    return this.http.get<{ items: InvimaCategory[] }>(`${this.apiBase}/categorias`);
  }

  getFilterOptions(): Observable<InvimaFiltersResponse> {
    return this.http.get<InvimaFiltersResponse>(`${this.apiBase}/filtros`);
  }

  searchCatalog(query: CatalogQuery): Observable<InvimaCatalogResponse> {
    let params = new HttpParams();

    if (query.q) params = params.set('q', query.q);
    if (query.categorias?.length) params = params.set('categorias', query.categorias.join(','));
    if (query.datasets?.length) params = params.set('datasets', query.datasets.join(','));
    if (query.estados?.length) params = params.set('estados', query.estados.join(','));
    if (query.modalidades?.length) params = params.set('modalidades', query.modalidades.join(','));
    if (query.grupos?.length) params = params.set('grupos', query.grupos.join(','));
    if (query.fechaVencDesde) params = params.set('fechaVencDesde', query.fechaVencDesde);
    if (query.fechaVencHasta) params = params.set('fechaVencHasta', query.fechaVencHasta);
    if (query.fechaExpDesde) params = params.set('fechaExpDesde', query.fechaExpDesde);
    if (query.fechaExpHasta) params = params.set('fechaExpHasta', query.fechaExpHasta);
    if (query.onlyVigentes) params = params.set('onlyVigentes', 'true');
    if (query.limit !== undefined) params = params.set('limit', String(query.limit));
    if (query.offset !== undefined) params = params.set('offset', String(query.offset));

    return this.http.get<InvimaCatalogResponse>(`${this.apiBase}/catalogo`, { params });
  }

  sync(datasets: string[], pageSize = 1000, concurrency = 4): Observable<InvimaSyncResponse> {
    return this.http.post<InvimaSyncResponse>(`${this.apiBase}/sync`, {
      datasets,
      pageSize,
      concurrency
    });
  }

  getSyncStats(datasets: string[] = []): Observable<InvimaSyncStats> {
    let params = new HttpParams();
    if (datasets.length) {
      params = params.set('datasets', datasets.join(','));
    }
    return this.http.get<InvimaSyncStats>(`${this.apiBase}/sync/stats`, { params });
  }

  getSyncJob(): Observable<{ ok: boolean; job: InvimaSyncJob | null }> {
    return this.http.get<{ ok: boolean; job: InvimaSyncJob | null }>(`${this.apiBase}/sync/job`);
  }

  exportCatalog(query: CatalogQuery, format: 'csv' | 'xlsx'): Observable<InvimaExportFile> {
    const params = this.buildExportParams(query, format);
    const fallbackFilename = this.buildFallbackFilename(format);

    return this.http
      .get(`${this.apiBase}/catalogo/export`, {
        params,
        observe: 'response',
        responseType: 'blob'
      })
      .pipe(
        map((response) => {
          const contentDisposition = response.headers.get('content-disposition');
          const contentType = response.headers.get('content-type') || 'application/octet-stream';
          const filename = this.extractFilename(contentDisposition, fallbackFilename);

          return {
            blob: response.body || new Blob([]),
            filename,
            contentType
          };
        })
      );
  }

  buildExportUrl(query: CatalogQuery, format: 'csv' | 'xlsx'): string {
    const params = this.buildExportParams(query, format);
    return `${this.apiBase}/catalogo/export?${params.toString()}`;
  }
}
