import {
  ChangeDetectionStrategy,
  Component,
  computed,
  input,
  output
} from '@angular/core';

export type ButtonType = 'button' | 'submit' | 'reset';

export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';

export type IconPosition = 'left' | 'right';

export type ButtonVariant =
  | 'primary'
  | 'primary-full'
  | 'secondary'
  | 'secondary-full'
  | 'success'
  | 'success-full'
  | 'danger'
  | 'danger-full'
  | 'warning'
  | 'warning-full'
  | 'info'
  | 'info-full'
  | 'light'
  | 'dark'
  | 'transparent'
  | 'custom';

export type ButtonAction =
  | 'add'
  | 'save'
  | 'submit'
  | 'update'
  | 'edit'
  | 'delete'
  | 'cancel'
  | 'close'
  | 'upload'
  | 'download'
  | 'import'
  | 'export'
  | 'view'
  | 'search'
  | 'refresh'
  | 'reset'
  | 'approve'
  | 'reject'
  | 'login'
  | 'next'
  | 'previous'
  | 'custom';

interface ButtonActionConfig {
  label: string;
  icon: string | null;
  variant: ButtonVariant;
  type: ButtonType;
}

const BUTTON_ACTION_CONFIG: Record<ButtonAction, ButtonActionConfig> = {
  add: {
    label: 'Add',
    icon: 'ri-add-line',
    variant: 'primary-full',
    type: 'button'
  },
  save: {
    label: 'Save',
    icon: 'ri-save-line',
    variant: 'primary-full',
    type: 'submit'
  },
  submit: {
    label: 'Submit',
    icon: 'ri-send-plane-line',
    variant: 'primary-full',
    type: 'submit'
  },
  update: {
    label: 'Update',
    icon: 'ri-save-3-line',
    variant: 'primary-full',
    type: 'submit'
  },
  edit: {
    label: 'Edit',
    icon: 'ri-edit-line',
    variant: 'primary-full',
    type: 'button'
  },
  delete: {
    label: 'Delete',
    icon: 'ri-delete-bin-line',
    variant: 'danger-full',
    type: 'button'
  },
  cancel: {
    label: 'Cancel',
    icon: 'ri-close-line',
    variant: 'light',
    type: 'button'
  },
  close: {
    label: 'Close',
    icon: 'ri-close-line',
    variant: 'light',
    type: 'button'
  },
  upload: {
    label: 'Upload',
    icon: 'ri-upload-cloud-2-line',
    variant: 'primary-full',
    type: 'button'
  },
  download: {
    label: 'Download',
    icon: 'ri-download-cloud-2-line',
    variant: 'success-full',
    type: 'button'
  },
  import: {
    label: 'Import',
    icon: 'ri-file-upload-line',
    variant: 'info-full',
    type: 'button'
  },
  export: {
    label: 'Export',
    icon: 'ri-file-download-line',
    variant: 'success-full',
    type: 'button'
  },
  view: {
    label: 'View',
    icon: 'ri-eye-line',
    variant: 'info-full',
    type: 'button'
  },
  search: {
    label: 'Search',
    icon: 'ri-search-line',
    variant: 'primary-full',
    type: 'button'
  },
  refresh: {
    label: 'Refresh',
    icon: 'ri-refresh-line',
    variant: 'light',
    type: 'button'
  },
  reset: {
    label: 'Reset',
    icon: 'ri-restart-line',
    variant: 'light',
    type: 'reset'
  },
  approve: {
    label: 'Approve',
    icon: 'ri-check-line',
    variant: 'success-full',
    type: 'button'
  },
  reject: {
    label: 'Reject',
    icon: 'ri-close-circle-line',
    variant: 'danger-full',
    type: 'button'
  },
  login: {
    label: 'Login',
    icon: 'ri-login-box-line',
    variant: 'primary-full',
    type: 'submit'
  },
  next: {
    label: 'Next',
    icon: 'ri-arrow-right-line',
    variant: 'primary-full',
    type: 'button'
  },
  previous: {
    label: 'Previous',
    icon: 'ri-arrow-left-line',
    variant: 'light',
    type: 'button'
  },
  custom: {
    label: '',
    icon: null,
    variant: 'custom',
    type: 'button'
  }
};

@Component({
  selector: 'app-button',
  standalone: true,
  templateUrl: './button.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class Button {
  /*
   * Action provides sensible defaults.
   * Explicit inputs below override action configuration.
   */
  readonly action = input<ButtonAction | null>(null);

  readonly label = input<string | null>(null);
  readonly icon = input<string | null>(null);

  readonly type = input<ButtonType | null>(null);
  readonly variant = input<ButtonVariant | null>(null);
  readonly size = input<ButtonSize>('md');

  readonly iconPosition = input<IconPosition>('left');
  readonly showIcon = input(true);
  readonly iconOnly = input(false);

  readonly loading = input(false);
  readonly loadingLabel = input<string | null>(null);
  readonly disabled = input(false);

  readonly fullWidth = input(false);
  readonly rounded = input(false);

  readonly className = input('');
  readonly iconClass = input('');

  readonly ariaLabel = input<string | null>(null);
  readonly title = input<string | null>(null);

  readonly buttonClicked = output<MouseEvent>();

  private readonly actionConfig = computed<ButtonActionConfig>(() => {
    const action = this.action();

    return action
      ? BUTTON_ACTION_CONFIG[action]
      : BUTTON_ACTION_CONFIG.custom;
  });

  readonly resolvedLabel = computed(() => {
    return this.label() ?? this.actionConfig().label;
  });

  readonly resolvedIcon = computed(() => {
    // Explicit icon overrides the action icon.
    return this.icon() ?? this.actionConfig().icon;
  });

  readonly resolvedType = computed<ButtonType>(() => {
    return this.type() ?? this.actionConfig().type ?? 'button';
  });

  readonly resolvedVariant = computed<ButtonVariant>(() => {
    const explicitVariant = this.variant();

    if (explicitVariant) {
      return explicitVariant;
    }

    const action = this.action();

    if (action) {
      return BUTTON_ACTION_CONFIG[action].variant;
    }

    return 'primary-full';
  });

  readonly isDisabled = computed(() => {
    return this.disabled() || this.loading();
  });

  readonly resolvedIconClass = computed(() => {
    return [
      this.resolvedIcon(),
      'align-middle leading-none',
      this.iconClass()
    ]
      .filter(Boolean)
      .join(' ');
  });

  readonly buttonClass = computed(() => {
    const variants: Record<ButtonVariant, string> = {
      primary: 'ti-btn-primary',
      'primary-full': 'ti-btn-primary-full',

      secondary: 'ti-btn-secondary',
      'secondary-full': 'ti-btn-secondary-full',

      success: 'ti-btn-success',
      'success-full': 'ti-btn-success-full',

      danger: 'ti-btn-danger',
      'danger-full': 'ti-btn-danger-full',

      warning: 'ti-btn-warning',
      'warning-full': 'ti-btn-warning-full',

      info: 'ti-btn-info',
      'info-full': 'ti-btn-info-full',

      light: 'ti-btn-light',
      dark: 'ti-btn-dark',
      transparent: 'bg-transparent',
      custom: ''
    };

    const sizes: Record<ButtonSize, string> = {
      xs: '!px-2 !py-1 !text-[0.6875rem]',
      sm: '!px-3 !py-1.5 !text-[0.75rem]',
      md: '',
      lg: 'ti-btn-lg'
    };

    return [
      'ti-btn',
      'inline-flex items-center justify-center',
      'cursor-pointer',
      variants[this.resolvedVariant()],
      sizes[this.size()],
      this.fullWidth() ? 'w-full' : '',
      this.iconOnly() ? '!p-0' : '',
      this.rounded() ? '!rounded-full' : '',
      this.isDisabled()
        ? 'cursor-not-allowed opacity-60'
        : 'cursor-pointer',
      this.className()
    ]
      .filter(Boolean)
      .join(' ');
  });

  onClick(event: MouseEvent): void {
    if (this.isDisabled()) {
      event.preventDefault();
      event.stopPropagation();
      return;
    }

    this.buttonClicked.emit(event);
  }
}