import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { StringUtils } from '../../utilities/string-utils';

// @Injectable({
//   providedIn: 'root'
// })
//@Injectable()
export interface ICrudService<T> {
  getAll(): Observable<T[]>
  getById(id: any): Observable<T>;
  update(data: T): Observable<boolean>;
  createOrUpdate(data: T): Observable<T>;
  createOrUpdateAll(data: T[]): Observable<T[]>;
  delete(id: any): Observable<T>;
}


export class CrudService<T> implements ICrudService<T> {

  protected apiUrlFunc: (id?: string) => string = () => '';
  private GET_URL_GET_ALL = () => `${this.apiUrlFunc()}/GetAll?`;
  private GET_URL_GET_BY_ID = (id) => `${this.apiUrlFunc()}/GetById?id=${id}`;
  private POST_URL_UPDATE = () => `${this.apiUrlFunc()}/Update`
  private POST_URL_CREATE_OR_UPDATE = () => `${this.apiUrlFunc()}/CreateOrUpdate`
  private POST_URL_CREATE_OR_UPDATE_ALL = () => `${this.apiUrlFunc()}/CreateOrUpdateAll`
  private DELETE_URL_DELETE = (id) => `${this.apiUrlFunc()}/Delete?id=${id}`;

  constructor(protected http: HttpClient, apiUrlFunc: (id?: string) => string) {
    this.apiUrlFunc = apiUrlFunc;
  }


  getAll() {
    return this.http.get<T[]>(this.GET_URL_GET_ALL());
  }

  getById(id: string) {
    return this.http.get<T>(this.GET_URL_GET_BY_ID(id));
  }

  update(data: T) {
    return this.http.post<boolean>(this.POST_URL_UPDATE(),
      JSON.stringify(data), {
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
    });

  }
  createOrUpdate(data: T) {
    return this.http.post<T>(this.POST_URL_CREATE_OR_UPDATE(),
      JSON.stringify(data), {
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
    });

  }
  createOrUpdateAll(data: T[]) {
    return this.http.post<T[]>(this.POST_URL_CREATE_OR_UPDATE_ALL(),
      JSON.stringify(data), {
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
    });

  }
  delete(id: string) {
    return this.http.delete<T>(this.DELETE_URL_DELETE(id));
  }

  private post(url: string, obj: any) {
    return this.http.post<boolean>(url, JSON.stringify(obj),
      {
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        }
      }
    );
  }
  private put(url: string, obj: any) {
    return this.http.put<boolean>(url, JSON.stringify(obj),
      {
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        }
      }
    );
  }
}


@Injectable({
  providedIn: 'root'
})
export class CombinedKeyCrudService<T> implements ICrudService<T> {

  protected apiUrlFunc: (id?: string) => string = () => '';
  private GET_URL_GET_ALL = () => `${this.apiUrlFunc()}/GetAll?`;
  private POST_URL_UPDATE = () => `${this.apiUrlFunc()}/Update`
  private POST_URL_CREATE_OR_UPDATE = () => `${this.apiUrlFunc()}/CreateOrUpdate`
  private POST_URL_CREATE_OR_UPDATE_ALL = () => `${this.apiUrlFunc()}/CreateOrUpdateAll`
  private GET_URL_GET_BY_ID = (ids: string[]) => `${this.apiUrlFunc()}/GetById?${StringUtils.arrayToUrlParams('ids', ids)}`;
  private DELETE_URL_DELETE = (ids: string[]) => `${this.apiUrlFunc()}/Delete?${StringUtils.arrayToUrlParams('ids', ids)}`;
  constructor(
    protected http: HttpClient, apiUrlFunc: (id?: string) => string) {
    this.apiUrlFunc = apiUrlFunc;
  }

  getAll() {
    return this.http.get<T[]>(this.GET_URL_GET_ALL());
  }

  getById(ids: string[]) {
    return this.http.get<T>(this.GET_URL_GET_BY_ID(ids));
  }

  update(data: T) {
    return this.http.post<boolean>(this.POST_URL_UPDATE(),
      JSON.stringify(data), {
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
    });

  }
  createOrUpdate(data: T) {
    return this.http.post<T>(this.POST_URL_CREATE_OR_UPDATE(),
      JSON.stringify(data), {
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
    });

  }
  createOrUpdateAll(data: T[]) {
    return this.http.post<T[]>(this.POST_URL_CREATE_OR_UPDATE_ALL(),
      JSON.stringify(data), {
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
    });

  }
  delete(ids: string[]) {
    return this.http.delete<T>(this.DELETE_URL_DELETE(ids));
  }

  private post(url: string, obj: any) {
    return this.http.post<boolean>(url, JSON.stringify(obj),
      {
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        }
      }
    );
  }
  private put(url: string, obj: any) {
    return this.http.put<boolean>(url, JSON.stringify(obj),
      {
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        }
      }
    );
  }

}
// // Type definitions
// type TextResponse = { message: string };
// /**
// * Base CRUD service that targets the provided controller path.
// *
// * It mirrors the endpoints of CrudBaseApiController<T>:
// * GET /api/{controller}
// * GET /api/{controller}/{id}
// * POST /api/{controller} -> string
// * POST /api/{controller}/batch -> string[]
// * PUT /api/{controller}
// * PUT /api/{controller}/batch -> number
// * DELETE /api/{controller}/{id}
// * DELETE /api/{controller}/batch -> text summary
// * GET /api/{controller}/{id}/exists -> boolean
// * GET /api/{controller}/count -> number
// */
// @Injectable({ providedIn: 'root' })
// export class CrudBaseApiService<T extends object> {
//     /**
//     * Example: baseUrl = 'https://your-api', controller = 'Customer' →
//     * endpoint = 'https://your-api/api/Customer'
//     */
//     protected readonly endpoint: string;


//     /**
//     * @param http Angular HttpClient
//     * @param baseUrl API root without trailing slash (e.g., environment.apiBaseUrl)
//     * @param controllerName Controller name (e.g., 'Customer', 'Orders')
//     */
//     constructor(
//         protected http: HttpClient,
//         protected apiConfig: ApiConfigService,
//         @Inject(String) private controllerName: string
//     ) {
//         this.endpoint = apiConfig.getApiUrl(this.controllerName);
//     }


//     /** Optional default headers (JSON). Override in subclasses if needed. */
//     protected get jsonHeaders(): HttpHeaders {
//         return new HttpHeaders({ 'Content-Type': 'application/json' });
//     }


//     /** Shared error handler that surfaces useful messages. */
//     protected handleError(error: HttpErrorResponse): Observable<never> {
//         let msg = 'Unknown error';
//         if (error.error instanceof Blob) {
//             // In case backend returns text/plain; charset=utf-8 as Blob
//             return throwError(() => new Error('Server returned an error blob'));
//         }
//         if (typeof error.error === 'string') msg = error.error;
//         else if (error.error?.message) msg = error.error.message;
//         else if (error.message) msg = error.message;
//         return throwError(() => new Error(msg));
//     }
//     /** Prepare the response for the given entity. Override in subclasses if needed. */
//     protected prepareResponse(response: T): T {
//         // Do nothing by default
//         return response;
//     }

//     /** GET /api/{controller} */
//     getAll(): Observable<T[]> {
//         return this.http
//             .get<T[]>(this.endpoint)
//             .pipe(
//                 map(response => {

//                     for (let i = 0; i < response.length; i++) {
//                         const element = response[i];
//                         response[i] = this.prepareResponse(element);
//                     }
//                     return response;
//                 }),
//                 catchError(err => this.handleError(err)));
//     }


//     /** GET /api/{controller}/{id} */
//     getById(id: string): Observable<T> {
//         return this.http
//             .get<T>(`${this.endpoint}/${id}`)
//             .pipe(
//                 map(response => this.prepareResponse(response)),
//                 catchError(err => this.handleError(err)));
//     }



//     /** POST /api/{controller} -> string */
//     create(entity: T): Observable<string> {
//         return this.http
//             .post<string>(this.endpoint, entity, { headers: this.jsonHeaders })
//             .pipe(catchError(err => this.handleError(err)));
//     }


//     /** POST /api/{controller}/batch -> string[] */
//     createRange(entities: T[]): Observable<string[]> {
//         return this.http
//             .post<string[]>(`${this.endpoint}/batch`, entities, { headers: this.jsonHeaders })
//             .pipe(catchError(err => this.handleError(err)));
//     }


//     /** PUT /api/{controller} */
//     update(entity: T): Observable<void> {
//         return this.http
//             .put<void>(this.endpoint, entity, { headers: this.jsonHeaders })
//             .pipe(catchError(err => this.handleError(err)));
//     }


//     /** PUT /api/{controller}/batch -> number (updated count) */
//     updateRange(entities: T[]): Observable<number> {
//         return this.http
//             .put<number>(`${this.endpoint}/batch`, entities, { headers: this.jsonHeaders })
//             .pipe(catchError(err => this.handleError(err)));
//     }


//     /** DELETE /api/{controller}/{id} */
//     delete(id: string): Observable<void> {
//         return this.http
//             .delete<void>(`${this.endpoint}/${id}`)
//             .pipe(catchError(err => this.handleError(err)));
//     }


//     /** DELETE /api/{controller}/batch -> text summary */
//     deleteRange(ids: string[]): Observable<TextResponse> {
//         // API returns a plain text message; map it into a TextResponse for convenience
//         return this.http
//             .delete(`${this.endpoint}/batch`, {
//                 body: ids,
//                 headers: this.jsonHeaders
//             })
//             .pipe(
//                 map((response: any) => ({ message: response || 'Batch delete completed' })),
//                 catchError(err => this.handleError(err))
//             );
//     }


//     /** GET /api/{controller}/{id}/exists -> boolean */
//     exists(id: string): Observable<boolean> {
//         return this.http
//             .get<boolean>(`${this.endpoint}/${id}/exists`)
//             .pipe(catchError(err => this.handleError(err)));
//     }


//     /** GET /api/{controller}/count -> number */
//     count(): Observable<number> {
//         return this.http
//             .get<number>(`${this.endpoint}/count`)
//             .pipe(catchError(err => this.handleError(err)));
//     }
// }
