import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { OdataGridHelper } from '../_shared/utils/odata-grid-helper';
import { map } from 'rxjs/operators';
import { IdName } from '../_shared/utils/util';
import { Observable, of } from 'rxjs';

export interface Report {
  id: number;
  name: string;
  selectedFilterId: number;
  filters: ReportFilter[];
  dataSourceSet: { [filterId: number]: DataSource[] };
  fileExtension: string;
  runDisabled: boolean;
  saveAsPdf: boolean;
  hasRequiredFilter: boolean;
}

export interface ReportFilter {
  id: number;
  name: string;
  hasRequiredFilterParams: boolean;
}

export interface ReportDetail {
  id: number;
  name: string;
  dataSourceIds: number[];
  templateFileNameOriginal: string;
  templateFileNameOnDisk: string;
  securityGroupIds: string;
  securityUserIds: string;
  notes: string;
}

export interface DataSource {
  id: number;
  name: string;
  itemFilters: DataSourceItemFilter[];
}

export interface DataSourceItemFilter {
  filterHeader: string;
  filterValues: string[];
}

export interface RequiredData {
  hasReportModifyPermission: boolean;
  securityGroups: IdName[];
  userInfos: IdName[];
  dataSources: IdName[];
}

@Injectable({
  providedIn: 'root'
})
export class ReportService extends OdataGridHelper {
  private baseUrl = `${window.location.origin}/api/Report`;
  http = inject(HttpClient);

  requiredData$ = this.http.get<RequiredData>(`${this.baseUrl}/getRequiredData`)

  getReports(showAll: boolean): Observable<Report[]> {
    const url = `${this.baseUrl}/getReports?showAll=${showAll}`;
    return this.http.get<Report[]>(url);
  }

  getReportDetail(reportId: number): Observable<ReportDetail> {
    const url = `${this.baseUrl}/getReportDetail?reportId=${reportId}`;
    return this.http.get<ReportDetail>(url);
  }

  runReport(reportId: number, filterId: number, saveAsPdf: boolean): Observable<{ fileBlob: Blob, fileName: string }> {
    const filterIdStr = filterId ?? '';
    const url = `${this.baseUrl}/runReport?reportId=${reportId}&filterId=${filterIdStr}&saveAsPdf=${saveAsPdf}`;
    return this.http.get(url, { observe: 'response', responseType: 'blob' }).pipe(
      map((result) => {
        const fileBlob = result.body;

        const contentDisposition = result.headers.get('content-disposition');

        // Extract the file name
        let fileName = contentDisposition
          ?.split(';')[1]
          ?.split('filename')[1]
          ?.split('=')[1]
          ?.trim()
          ?.match(/"([^"]+)"/)[1] ?? 'Error.txt';

        fileName = result.body.type === "text/plain" ? "Error.txt" : fileName;
        return { fileBlob, fileName };
      })
    );
  }

  saveReportDetail(reportDetail: ReportDetail): Observable<number> {
    if (reportDetail) {
      const url = `${this.baseUrl}/SaveReportDetail`;
      return this.http.put<number>(url, reportDetail);
    } else {
      return of(0);
    }
  }

  deleteReport(id: number) {
    const url = `${this.baseUrl}/DeleteReport/${id}`;
    return this.http.delete(url);
  }

  saveReportTemplate(fileItem: unknown) {
    const url = `${this.baseUrl}/SaveReportTemplate`;
    return this.http.put(url, fileItem);
  }

  downloadReportTemplate(reportId: number, fileNameOriginal: string, fileNameOnDisk: string): Observable<{ fileBlob: Blob, fileName: string }> {
    const url = `${this.baseUrl}/DownloadReportTemplate?reportId=${reportId}&fileNameOnDisk=${fileNameOnDisk}`;
    return this.http.get(url, { observe: 'response', responseType: 'blob' }).pipe(
      map(result => {
        const fileBlob = result.body;
        const fileName: string = result.body.type === "text/plain" ? "Error.txt" : fileNameOriginal;
        return { fileBlob, fileName };
      })
    );
  }

  setSaveAsPdf(reportId: number, saveAsPdf: boolean) {
    const url = `${this.baseUrl}/SetSaveAsPdf?reportId=${reportId}&saveAsPdf=${saveAsPdf}`;
    return this.http.put(url, null);
  }
}
