import { CommonModule } from "@angular/common";
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, effect, ElementRef, HostBinding, inject, input, OnChanges, output, signal, ViewChild } from "@angular/core";
import * as util from '../utils/util';
import { FAST_KENDO_COMMON, FAST_PAGE_COMMON } from "../../app.config";
import { twMerge } from 'tailwind-merge';
import { FastButtonGroupComponent } from "./fast-buttongroup.component";

type ButtonType = 'basic' | 'delete' | 'export' | 'primary' | 'transparent' | 'success' | 'fail';

@Component({
  selector: 'fast-button',
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: true,
  imports: [CommonModule, FAST_KENDO_COMMON, FAST_PAGE_COMMON],
  template: `
  @if(type() === 'export'){
    <button #buttonElem [ngClass]="conditionalClasses()" type="button" [disabled]="isDisabled()"
      [value]="value()" [hidden]="exporting()" [tabIndex]="tabIndex()">
      <fast-svg class="mr-0.5" [size]="18" icon="excelFile" fillColor="initial" strokeColor="none"/>Export
    </button>
    <button [ngClass]="conditionalClasses()" type="button" [disabled]="isDisabled()"
      [value]="value()" [disabled]="true" [hidden]="!exporting()" [tabIndex]="-1">
      Exporting...
    </button>
    }
  @else {
    <button #buttonElem [ngClass]="conditionalClasses()" type="button" [disabled]="isDisabled()"
      [value]="value()" (click)="onSelect()" [tabIndex]="tabIndex()">
      <ng-content></ng-content>
    </button>
  }
  `
})
export class FastButtonComponent implements OnChanges {
  @ViewChild("buttonElem") buttonElem: ElementRef<HTMLButtonElement>;

  cdr = inject(ChangeDetectorRef);
  util = util;

  type = input<ButtonType>('basic');
  disabled = input<boolean>(false);
  value = input<string>('');
  exporting = input<boolean>(false);
  class = input<string>('');
  toggleable = input<boolean>(false);
  private localSelected = signal<boolean>(false); // specifically to track local changes if the button is standalone
  selectedInput = input<boolean>();
  selectedChange = output<boolean>();
  defaultClasses = 'flex w-28 h-7.5';
  tabIndex = input<number>(0);

  constructor() {
    effect(() => {
      this.localSelected.set(this.selectedInput());
      // sync initial state to the group
      if (this.selectedInput() && this.buttonGroup) {
        this.buttonGroup.writeValue(this.value());
      }
    });
  }

  // Button Group external ref, should be private so it's per button
  private readonly buttonGroup = inject(FastButtonGroupComponent, {
    optional: true,
    host: true
  });

  readonly selected = computed(() => {
    return this.buttonGroup?.isSelected(this.value()) ?? this.localSelected();
  });

  // Internal signal to track form control disabled state
  private formControlDisabled = signal<boolean>(false);

  // Computed signal that combines input disabled state and form control disabled state
  isDisabled = computed(() => {
    const groupDisabled = this.buttonGroup?.isDisabled() ?? false;
    return this.disabled() || this.formControlDisabled() || groupDisabled;
  });

  onSelect() {
    if (this.buttonGroup) {
      if (this.isDisabled()) return;
      this.buttonGroup.selectItem(this.value());
      this.selectedChange.emit(this.buttonGroup.isSelected(this.value()));
      return;
    }

    if (this.toggleable()) {
      this.localSelected.update(val => {
        const newVal = !val;
        this.selectedChange.emit(newVal); // Emit boolean
        return newVal;
      });
    }
  }

  @HostBinding('class') hostClass: string = this.defaultClasses;

  ngOnChanges(): void {
    this.hostClass = twMerge(this.defaultClasses, this.class());
  }

  setDisabledState(isDisabled: boolean) {
    this.formControlDisabled.set(isDisabled);
    this.cdr.markForCheck();
  }

  conditionalClasses = computed(() => {
    const classes = [] as string[];

    classes.push(...this.getCommonClasses());
    classes.push(...this.getLightBaseClasses(this.type()));
    classes.push(...this.getDarkBaseClasses(this.type()));
    if (!this.isDisabled()) {
      classes.push(...this.getLightHoverClasses(this.type()));
      classes.push(...this.getDarkHoverClasses(this.type()));
      classes.push(...this.getLightActiveClasses(this.type()));
      classes.push(...this.getDarkActiveClasses(this.type()));
    }

    const conditionalClasses = this.getConditionalClassesFromArrays(classes);
    return conditionalClasses;
  });

  getConditionalClassesFromArrays(classArray: string[]): { [key: string]: boolean } {
    const classes: { [key: string]: boolean } = {};
    classArray.forEach(className => {
      classes[className] = true;
    });
    return classes;
  }

  getCommonClasses() {
    const commonClasses = [] as string[];
    commonClasses.push(
      "flex",
      "grow",
      "text-sm",
      "leading-0",
      "pl-2",
      "pr-2",
      "pt-1",
      "pb-1",
      "gap-1",
      "items-center",
      "justify-center",
      "cursor-pointer",
    );
    if ((!this.buttonGroup) && !(this.type() === 'transparent')) {
      commonClasses.push(
        "rounded-md",
        "border-solid",
        "border-1");
    }
    return commonClasses;
  }

  getLightBaseClasses(type: ButtonType) {
    const lightBase = ["text-base-black-1000", "border-base-gray-1000"]
    if (this.selected()) {
      lightBase.push("bg-base-blue-250", "sepia");
      return lightBase;
    }

    if (type == 'basic' || type == 'export')
      lightBase.push("bg-gradient-to-b", "from-base-white-250", "via-base-blue-250", "to-base-blue-250");

    if (type == 'primary')
      lightBase.push("bg-gradient-to-b", "from-base-white-250", "via-base-blue-250", "to-base-white-250");

    if (type == 'delete')
      lightBase.push("bg-gradient-to-b", "from-base-white-250", "via-base-red-250", "to-base-red-500");

    if (type == 'success')
      lightBase.push("bg-gradient-to-b", "from-base-white-250", "via-green-200", "to-green-400");

    if (type == 'fail')
      lightBase.push("bg-gradient-to-b", "from-base-white-250", "via-base-yellow-250", "to-base-yellow-500");

    return lightBase;
  }

  getDarkBaseClasses(type: ButtonType) {
    const darkBase = ["dark:text-base-white-500", "dark:border-alt-white-1000"]
    if (this.selected()) {
      darkBase.push("dark:bg-alt-blue-250", "dark:sepia");
      return darkBase;
    }

    if (type == 'basic' || type == 'export')
      darkBase.push("dark:bg-gradient-to-b", "dark:from-alt-blue-250", "dark:via-alt-gray-1000", "dark:to-alt-blue-750");

    if (type == 'primary')
      darkBase.push("dark:bg-gradient-to-b", "dark:from-base-blue-250", "dark:via-alt-gray-1000", "dark:to-alt-blue-750");

    if (type == 'delete')
      darkBase.push("dark:bg-gradient-to-b", "dark:from-alt-red-500", "dark:via-base-black-1000", "dark:to-base-black-1000");

    if (type == 'success')
      darkBase.push("dark:bg-gradient-to-b", "dark:from-green-500", "dark:via-alt-gray-500", "dark:to-green-700");

    if (type == 'fail')
      darkBase.push("dark:bg-gradient-to-b", "dark:from-yellow-600", "dark:via-alt-gray-1000", "dark:to-yellow-700");

    return darkBase;
  }

  getLightHoverClasses(type: ButtonType) {
    if (type === 'transparent')
      return ["hover:bg-white/30"];

    return ["hover:text-alt-blue-250", "hover:border-alt-blue-250", "hover:brightness-90"];
  }

  getDarkHoverClasses(type: ButtonType) {
    if (type === 'transparent')
      return ["dark:hover:bg-black/30"];

    return ["dark:hover:brightness-150", "dark:hover:text-base-blue-250", "dark:hover:border-base-blue-250"];
  }

  getLightActiveClasses(type: ButtonType) {
    if (type == 'basic' || type == 'export')
      return ["active:bg-gradient-to-b", "active:from-base-blue-250", "active:via-base-blue-250", "active:to-base-white-250", "active:hover:sepia"];

    if (type == 'primary')
      return ["active:bg-gradient-to-b", "active:from-base-blue-250", "active:via-base-white-250", "active:to-base-blue-250", "active:hover:sepia"];

    if (type == 'delete')
      return ["active:bg-gradient-to-b", "active:from-base-red-500", "active:via-base-red-250", "active:to-base-white-250", "active:hover:sepia"];

    if (type == 'transparent')
      return ["active:bg-gradient-to-b", "active:from-base-white-1000", "active:via-base-white-1000", "active:to-base-white-250", "active:hover:sepia"];

    if (type == 'success')
      return ["active:bg-gradient-to-b", "active:from-green-500", "active:via-green-250", "active:to-base-white-250", "active:hover:sepia"];

    if (type == 'fail')
      return ["active:bg-gradient-to-b", "active:from-base-yellow-500", "active:via-base-yellow-250", "active:to-base-white-250", "active:hover:sepia"];
  }

  getDarkActiveClasses(type: ButtonType) {
    if (type == 'basic' || type == 'export')
      return ["dark:active:bg-gradient-to-b", "dark:active:from-alt-blue-750", "dark:active:via-alt-gray-1000", "dark:active:to-alt-blue-250", "active:hover:sepia"];

    if (type == 'primary')
      return ["dark:active:bg-gradient-to-b", "dark:active:from-alt-blue-750", "dark:active:via-alt-gray-1000", "dark:active:to-base-blue-250", "active:hover:sepia"];

    if (type == 'delete')
      return ["dark:active:bg-gradient-to-b", "dark:active:from-base-black-1000", "dark:active:via-base-black-1000", "dark:active:to-alt-red-500", "active:hover:sepia"];

    if (type == 'transparent')
      return ["dark:active:bg-gradient-to-b", "dark:active:from-alt-gray-1000", "dark:active:via-alt-gray-1000", "dark:active:to-alt-gray-500", "active:hover:sepia"];

    if (type == 'success')
      return ["dark:active:bg-gradient-to-b", "dark:active:from-green-700", "dark:active:via-alt-gray-1000", "dark:active:to-green-900", "active:hover:sepia"];

    if (type == 'fail')
      return ["dark:active:bg-gradient-to-b", "dark:active:from-yellow-800", "dark:active:via-alt-gray-1000", "dark:active:to-yellow-900", "active:hover:sepia"];
  }
}
