import { Component } from '@angular/core';
import {
  faArrowDown,
  faArrowUp,
  faRemove,
  faSort,
  faSortAsc,
  faSortDesc,
  faSortDown,
} from '@fortawesome/free-solid-svg-icons';
import { SORT } from '../../enums/sort';
import { Action } from '../../models/action';
import { Header } from '../../models/header';
import { Query } from '../../models/query';
import { TreeNode } from '../../models/tree-node';
import { ExecuteService } from '../../services/execute.service';
import { QueryService } from '../../services/query.service';
import { TreeComponent } from '../tree/tree.component';

@Component({
  selector: 'fbi-query',
  standalone: true,
  imports: [TreeComponent],
  templateUrl: './query.component.html',
  styleUrl: './query.component.scss',
})
export class QueryComponent {
  node: TreeNode = new TreeNode({});

  constructor(
    private queryService: QueryService,
    executeService: ExecuteService
  ) {
    queryService.Query$.subscribe((query: Query) => {
      const headers = executeService.headers(query);
      const fields = this.getFields(query, headers);
      const filters = this.getFilters(query, headers);
      const sort = this.getSorts(query, headers);
      this.node = new TreeNode({
        hidden: true,
        expanded: true,
        children: [
          {
            label: 'Fields',
            leaf: false,
            expanded: true,
            children: fields,
          },
          {
            label: 'Filters',
            expanded: true,
            leaf: false,
            hidden: filters.length === 0,
            children: filters,
          },
          {
            label: 'Sort',
            expanded: true,
            leaf: false,
            hidden: sort.length === 0,
            children: sort,
          },
        ] as TreeNode[],
      });
    });
  }

  onActionClick(event: { action: Action; node: TreeNode }): void {
    const data = event.action.data as ActionData;
    switch (data.cmd) {
      case ACTIONS.REMOVE:
        this.queryService.remove(event.node.data);
        break;
      case ACTIONS.UP:
      case ACTIONS.DOWN:
        this.queryService.add(event.node.data, data.data);
        break;
      case ACTIONS.SORTASC:
      case ACTIONS.SORTDSC:
      case ACTIONS.SORTDEL:
        this.queryService.sort(data.data);
        break;
    }
  }

  private getFields(query: Query, headers: Header[]): Partial<TreeNode>[] {
    return (query?.fields ?? []).map(
      (field: string, index: number, array: string[]) => {
        const sort = query?.sort?.field ?? '';
        const sdir = query?.sort?.dir ?? SORT.NONE;

        const actions = [];
        // move
        if (index !== 0) {
          actions.push({
            label: 'Move Up',
            icon: faArrowUp,
            data: { cmd: ACTIONS.UP, data: index - 1 },
          });
        }
        if (index !== array.length - 1) {
          actions.push({
            label: 'Move Down',
            icon: faArrowDown,
            data: { cmd: ACTIONS.DOWN, data: index + 1 },
          });
        }

        // sort
        if (sort === field) {
          switch (sdir) {
            case SORT.ASC:
              actions.push({
                label: 'Sort Dsc',
                icon: faSortDown,
                data: { cmd: ACTIONS.SORTDSC, data: field },
              });
              break;
            case SORT.DSC:
              actions.push({
                label: 'Clear Sort',
                icon: faSort,
                data: { cmd: ACTIONS.SORTDEL, data: field },
              });
              break;
            default:
              actions.push({
                label: 'Sort Asc',
                icon: faSortAsc,
                data: { cmd: ACTIONS.SORTASC, data: field },
              });
              break;
          }
        } else {
          actions.push({
            label: 'Sort Asc',
            icon: faSortAsc,
            data: { cmd: ACTIONS.SORTASC, data: field },
          });
        }

        // remove
        actions.push({
          label: 'Remove',
          icon: faRemove,
          data: { cmd: ACTIONS.REMOVE },
        });

        const label =
          headers.find((header: Header) => header.source === field)?.label ??
          'unknown';

        return {
          label: label,
          data: field,
          actions: actions,
        };
      }
    );
  }

  private getFilters(query: Query, headers: Header[]): Partial<TreeNode>[] {
    return [];
  }

  private getSorts(query: Query, headers: Header[]): Partial<TreeNode>[] {
    const result: Partial<TreeNode>[] = [];

    if (query?.sort?.isValid?.()) {
      const s = query.sort;
      const label =
        headers.find((header: Header) => header.source === s.field)?.label ??
        'unknown';
      const actions = [];

      if (s.dir === SORT.ASC) {
        actions.push({
          label: 'Sort Dsc',
          icon: faSortDesc,
          data: { cmd: ACTIONS.SORTDSC, data: s.field },
        });
      } else if (s.dir === SORT.DSC) {
        actions.push({
          label: 'Clear Sort',
          icon: faSort,
          data: { cmd: ACTIONS.SORTDEL, data: s.field },
        });
      }

      result.push({
        label: label,
        data: s.field,
        actions: actions,
      });
    }

    return result;
  }
}

enum ACTIONS {
  REMOVE = 'del',
  UP = 'up',
  DOWN = 'down',
  SORTDSC = 'dsc',
  SORTASC = 'asc',
  SORTDEL = 'nne',
}

type ActionData = {
  cmd: ACTIONS;
  data: any;
};
