import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from '@msfa-environment';
import { Params } from '@msfa-models/api/params.model';
import { UtforandeVerksamhetResponse } from '@msfa-models/api/utforande-verksamhet.response.model';
import { EmployeeUtforandeVerksamhet } from '@msfa-models/employee-utforande-verksamhet.model';
import { UtforandeAdress } from '@msfa-models/utforande-adress.model';
import { mapResponseToUtforandeVerksamhet, UtforandeVerksamhet } from '@msfa-models/utforande-verksamhet.model';
import {
  TreeNode,
  TreeNodesSelectorService,
} from '@msfa-shared/components/tree-nodes-selector/services/tree-nodes-selector.service';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root',
})
export class UtforandeVerksamheterService {
  private readonly _apiBaseUrl = `${environment.api.url}/utforandeverksamheter`;

  constructor(private treeNodesSelectorService: TreeNodesSelectorService, private httpClient: HttpClient) {}

  fetchUtforandeVerksamheter$(tjanstIds: number[]): Observable<UtforandeVerksamhet[]> {
    if (!tjanstIds?.length) {
      return of<UtforandeVerksamhet[]>([]);
    }

    const params: Params = { tjansteIds: tjanstIds.map(tjanstId => tjanstId.toString()) };

    return this.httpClient
      .get<{ data: UtforandeVerksamhetResponse[] }>(`${this._apiBaseUrl}`, { params })
      .pipe(map(({ data }) => data.map(uv => mapResponseToUtforandeVerksamhet(uv))));
  }

  getSelectedAdressIdsFromTreeNode(treeNode: TreeNode): number[] {
    const selectedUtforandeVerksamheter = this.getSelectedUtforandeVerksamheterFromTreeNode(treeNode);

    return selectedUtforandeVerksamheter.map(uv => uv.adresser.map(adress => adress.id)).flat();
  }

  getTreeNodeDataFromUtforandeVerksamheter(
    availableUtforandeVerksamhetList: UtforandeVerksamhet[],
    selectedUtforandeVerksamhetList: EmployeeUtforandeVerksamhet[]
  ): TreeNode | null {
    let treeNode: TreeNode | null = null;

    if (
      !availableUtforandeVerksamhetList ||
      availableUtforandeVerksamhetList.length === 0 ||
      !Array.isArray(availableUtforandeVerksamhetList)
    ) {
      return treeNode;
    }

    treeNode = {
      label: 'Utförande Verksamheter',
      grandChildrenItemType: 'Adresser',
      grandChildrenInfo: 'Här kan du välja adresser när du valt en verksamhet till vänster.',
      isSelected: false,
      value: null,
      childItemType: 'Utförande verksamheter',
      children: availableUtforandeVerksamhetList.map(
        (utforandeVerksamhet: UtforandeVerksamhet): TreeNode => {
          const utforandeVerksahmetTreeNode: TreeNode = {
            label: utforandeVerksamhet.name,
            toggleAllChildrenLabel: 'Välj alla adresser',
            isSelected: this.isSelectedUtforandeVerksamhet(utforandeVerksamhet, selectedUtforandeVerksamhetList),
            value: utforandeVerksamhet,
            childItemType: 'Adresser',
            children: utforandeVerksamhet.adresser
              ? utforandeVerksamhet.adresser.map(adress => {
                  return {
                    label: adress.name,
                    isSelected: this.isSelectedUtforandeAdress(
                      utforandeVerksamhet.id,
                      adress,
                      selectedUtforandeVerksamhetList
                    ),
                    value: adress,
                  };
                })
              : [],
          };

          return utforandeVerksahmetTreeNode;
        }
      ),
    };

    return treeNode;
  }

  isSelectedUtforandeVerksamhet(
    utforandeVerksamhet: UtforandeVerksamhet,
    selectedUtforandeVerksamhetList: EmployeeUtforandeVerksamhet[]
  ): boolean {
    if (
      !utforandeVerksamhet ||
      !selectedUtforandeVerksamhetList ||
      selectedUtforandeVerksamhetList.length === 0 ||
      !Array.isArray(selectedUtforandeVerksamhetList)
    ) {
      return false;
    }

    return selectedUtforandeVerksamhetList.some(
      selectedUtforandeVerksamhet => selectedUtforandeVerksamhet.id === utforandeVerksamhet.id
    );
  }

  isSelectedUtforandeAdress(
    utforandeVerksamhetId: number,
    utforandeAdress: UtforandeAdress,
    selectedUtforandeVerksamhetList: EmployeeUtforandeVerksamhet[]
  ): boolean {
    let selectedUtforandeVerksamhet: EmployeeUtforandeVerksamhet | null = null;

    if (
      !utforandeAdress ||
      !selectedUtforandeVerksamhetList ||
      selectedUtforandeVerksamhetList.length === 0 ||
      !Array.isArray(selectedUtforandeVerksamhetList)
    ) {
      return false;
    }

    selectedUtforandeVerksamhet = selectedUtforandeVerksamhetList.find(
      selectedUtforandeVerksamhet => selectedUtforandeVerksamhet.id === utforandeVerksamhetId
    );

    return selectedUtforandeVerksamhet
      ? selectedUtforandeVerksamhet.allaAdresser ||
          selectedUtforandeVerksamhet.adresser.some(
            selectedUtforandeAdress => selectedUtforandeAdress.id === utforandeAdress.id
          )
      : false;
  }

  getSelectedUtforandeVerksamheterFromTreeNode(treeNode: TreeNode): UtforandeVerksamhet[] {
    let utforandeVerksamhetList: UtforandeVerksamhet[] = [];

    if (!treeNode || !treeNode.children) {
      return utforandeVerksamhetList;
    }

    utforandeVerksamhetList = this.treeNodesSelectorService
      .getTreeNodeFilteredBySelectedLeafOrDecsendants(treeNode)
      ?.children?.map(utforandeVerksamhetNode => {
        const originalUtforandeVerksamhet = utforandeVerksamhetNode.value as UtforandeVerksamhet;
        const utforandeVerksamhet: UtforandeVerksamhet = {
          name: originalUtforandeVerksamhet?.name,
          id: originalUtforandeVerksamhet?.id,
          adresser: utforandeVerksamhetNode.children.map(adressNode => {
            return adressNode.value as UtforandeAdress;
          }),
        };
        return utforandeVerksamhet;
      });

    return utforandeVerksamhetList ? utforandeVerksamhetList : [];
  }

  hasSelectedUtforandeVerksamhet = (treeNode: TreeNode): boolean => {
    if (!treeNode || !treeNode.children || treeNode.children.length === 0) {
      return false;
    }

    return treeNode.children.some(childNode => this.treeNodesSelectorService.hasSelectedLeafNodeDescendant(childNode));
  };
}
