import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Constants } from '../../Constants';
import { ICollectionData, CollectionNames, ICollectionFindParams } from '../data-model/ICollection';


@Injectable({
  providedIn: 'root',
})
export class CollectionDataService<T = any, J = any> {
  private apiUrl = `${Constants.ApiBase}/collection-data`;

  constructor(private http: HttpClient) {}

  // Get all data entries for a specific collection
  /// @param collectionId The ID of the collection to retrieve data from
  /// @param childrenCollection Whether to include children collections example collectionId=variations&childrenCollection=variations_options
  /// @returns An observable of ICollectionData array
  getDataByCollectionId(
    collectionId: string,
    childrenCollection = ''
  ): Observable<ICollectionData<T, J>[]> {
    const url = `${this.apiUrl}/list.php?collectionId=${collectionId}&childrenCollection=${childrenCollection}&websiteId=${CollectionNames.WebsiteId}`;
    return this.http.get<ICollectionData<T, J>[]>(url);
  }

  getChildren(
    parentId: number,
    collectionId: string = ''
  ): Observable<ICollectionData<T, J>[]> {
    const url = `${this.apiUrl}/get-children.php?parentId=${parentId}&collectionId=${collectionId}`;
    return this.http.get<ICollectionData<T, J>[]>(url);
  }
  getWithChildren(parentId: number) {
    const url = `${this.apiUrl}/get-with-children.php?parentId=${parentId}`;
    return this.http.get<ICollectionData<T, J>>(url);
  }

  getUserCollections(
    collectionId: CollectionNames,
    websiteId: string = CollectionNames.WebsiteId,
    limit: number = 1000,
    offset: number = 0,
    sortBy: string = 'id',
    sortOrder: 'ASC' | 'DESC' = 'DESC'
  ) {
    const base = `${Constants.ApiBase}/user-collection-data/list.php`;
    let url = `${base}?collectionId`;
    url += `=${collectionId}&websiteId=${websiteId}`;
    url += `&limit=${limit}&offset=${offset}`;
    url += `&sortBy=${sortBy}&sortOrder=${sortOrder}`;
    return this.http.get<ICollectionData<T, J>[]>(url);
  }

  //find-parents-that-have-children.php
  findParentsThatHaveChildren(
    collectionId: string
  ): Observable<ICollectionData<T, J>[]> {
    const url = `${this.apiUrl}/find-parents-that-have-children.php?collectionId=${collectionId}&websiteId=${CollectionNames.WebsiteId}`;
    return this.http.get<ICollectionData<T, J>[]>(url);
  }

  // Get a data entry by ID
  getDataById(id: number | string): Observable<ICollectionData<T, J>> {
    const url = `${this.apiUrl}/get.php?id=${id}`;
    return this.http.get<ICollectionData<T, J>>(url);
  }

  // Get a data entry by slug
  getDataBySlug(slug: string): Observable<ICollectionData<T, J>> {
    return this.getDataById(slug);
  }

  // Get all data entries for a specific collection with pagination
  categoryTree<T, J>(): Observable<ICollectionData<T, J>[]> {
    const url = `${this.apiUrl}/category-tree.php`;
    return this.http.get<ICollectionData<T, J>[]>(url);
  }

  // Advanced filter/sort/paginate search against any collection
  find<R = T>(params: ICollectionFindParams): Observable<ICollectionData<R>[]> {
    return this.http.post<ICollectionData<R>[]>(`${this.apiUrl}/find.php`, params);
  }

  // Add a new data entry
  addData(data: ICollectionData<T, J>): Observable<ICollectionData<T, J>> {
    const url = `${this.apiUrl}/save.php`;
    return this.http.post<ICollectionData<T, J>>(url, data);
  }

  // Update a data entry
  updateData(data: ICollectionData<T, J>): Observable<ICollectionData<T, J>> {
    const url = `${this.apiUrl}/save.php`;
    return this.http.put<ICollectionData<T, J>>(url, data);
  }

  // Delete a data entry by ID
  deleteData(id: number): Observable<any> {
    const url = `${this.apiUrl}/delete.php?id=${id}`;
    return this.http.delete(url);
  }

  // Delete all data entries for a specific collection
  deleteDataByCollectionId(collectionId: number): Observable<any> {
    const url = `${this.apiUrl}/delete.php?collection_id=${collectionId}`;
    return this.http.delete(url);
  }
}


import { Component, inject } from '@angular/core';
import { CollectionDataService } from './collection.data.service';
import { CollectionNames, ICollectionData } from '../data-model/ICollection';
interface ExapleData {
  name: string;
  value: string;
}
// This is an example component to demonstrate how to use the CollectionDataService
// Do not create a new service for each collection, use this generic service to perform CRUD operations on any collection by passing the collection name and data type.
@Component({
  selector: 'app-example',
  template: `<p>Example Component</p>`,
})
export class ExampleComponent {
  data: ICollectionData<ExapleData>[] = [];
  private dataService = inject(CollectionDataService<ExapleData>);
  list() {
    this.dataService
      .getDataByCollectionId(CollectionNames.Example)
      .subscribe((data) => {
        this.data = data;
      });
  }

  addExampleData() {
    const newData: ICollectionData<ExapleData> = {
      parent_id: 0,
      id: 0,
      website_id: CollectionNames.WebsiteId,
      collection_id: CollectionNames.Example,
      data: {
        name: 'Example Name',
        value: 'Example Value',
      },
    };
    this.dataService.addData(newData).subscribe(() => {
      this.list();
    });
  }

  updateExampleData(id: number) {
    const updatedData: ICollectionData<ExapleData> = {
      parent_id: 0,
      id: id,
      website_id: CollectionNames.WebsiteId,
      collection_id: CollectionNames.Example,
      data: {
        name: 'Updated Name',
        value: 'Updated Value',
      },
    };
    this.dataService.updateData(updatedData).subscribe(() => {
      this.list();
    });
  }

  deleteExampleData(id: number) {
    this.dataService.deleteData(id).subscribe(() => {
      this.list();
    });
  }

  getExampleDataById(id: number) {
    this.dataService.getDataById(id).subscribe((data) => {
      console.log(data);
    });
  }

  getChildrenData(parentId: number) {
    this.dataService.getChildren(parentId, CollectionNames.ExampleSubCollection).subscribe((data) => {
      console.log(data);
    });
  }
}


// Now we need to create:

/**

1. Create Website component that uses the CollectionDataService to fetch and display website data (pages, sections, blocks) from the database instead of using mock data.
2. Implement CRUD operations for pages, sections, and blocks using the CollectionDataService.
3. Update the editor to use the CollectionDataService for saving changes to the database instead of updating the mock data.
4. Ensure that all data fetching and mutations are done through the CollectionDataService to maintain a single source of truth for data management in the application.

Website -> Pages (ParentId = WebsiteId) -> Sections

Sections -> Embeds Conatiner (maxWidth, padding, etc) and ContentBlocks (type, content)

Call Flow
1. Get a website by id (user friendly slug)
2. Get Children of the website (pages) getChildren('websiteId', CollectionNames.Pages)  // We need all pages for Navigation and to build the tree view in the editor sidebar`
3. Get Children of current page only (sections) getChildren('currentPageId', CollectionNames.Sections)

Saving Updates:
1. When a block is updated in the editor, we save the whole section sing container and content blocks as JSON in the data field of the collection. This way we can easily fetch and render the entire section with all its blocks in one go, and we can also easily update individual blocks by updating the section data.


 */



import { Website } from './../../app/models/page.models';
export type FilterOperator = 'equals' | 'contains' | 'greater_than' | 'less_than' | 'in';
export type FilterType = 'string' | 'number' | 'date';

export interface ICollectionFilter {
  field: string;
  operator: FilterOperator;
  value: any;
  type?: FilterType;
}

export interface ICollectionFindParams {
  collection_id: string;
  website_id: string;
  filters?: ICollectionFilter[];
  sortBy?: string;
  sortOrder?: 'ASC' | 'DESC';
  limit?: number;
  offset?: number;
}

export interface ICollectionData<T = any, J = any> {
  parent_id: number;
  website_id: string;
  id: number;
  slug?: string;
  collection_id: CollectionIds; // e.g., 'example', 'settings', etc.
  data: T; // JSON data (inputs, styles, etc.)
  created_at?: string;
  updated_at?: string;
  selected?: boolean; // Used for checkboxes
  children?: ICollectionData<J>[]; // For hierarchical data
}
export type CollectionIds =
  | 'example'
  | 'settings'
  | 'website'
  | 'page'
  | 'section';

export enum CollectionNames {
  WebsiteId = 'structio',
  Example = 'example',
  ExampleSubCollection = 'example-sub-collection',
  Settings = 'settings',
  Website = 'website',
  Page = 'page',
  Section = 'section',
}
