import { Maybe } from '@/core';
import { PaginatorComponent, UikitCopyComponent, UikitEmptyStateComponent } from '@/uikit';
import { formatJalali, formatWithCurrency, jalaliDiff } from '@/utils';
import { CommonModule } from '@angular/common';
import {
  Component,
  computed,
  ContentChild,
  ElementRef,
  EventEmitter,
  Input,
  Output,
  Renderer2,
  signal,
  TemplateRef,
} from '@angular/core';
import { ButtonModule } from 'primeng/button';
import { DrawerModule } from 'primeng/drawer';
import { PaginatorModule } from 'primeng/paginator';
import { SkeletonModule } from 'primeng/skeleton';
import { TableModule } from 'primeng/table';
import { KeyValueComponent } from '../key-value.component/key-value.component';
import { TableActionRowComponent } from '../table-action-row.component';

type TDataType = 'simple' | 'price' | 'boolean' | 'date' | 'nested' | 'index' | 'id' | 'thumbnail';
export interface IColumn<T = any> {
  field: T extends object ? keyof T | string : string;
  header: string;
  width?: string;
  minWidth?: string;
  canCopy?: boolean;
  type?: TDataType;

  nestedOption?: {
    path: string;
    type?: TDataType;
  };
  thumbnailOptions?: {
    editable: boolean;
    deletable: boolean;
    showPreview: boolean;
  };
  dateOption?: {
    expiredMode?: boolean;
    dateTime?: boolean;
    onlyTime?: boolean;
  };
  customDataModel?: TemplateRef<any> | ((item: T) => string | number | boolean);
}

@Component({
  selector: 'app-page-data-list',
  templateUrl: './page-data-list.component.html',
  host: {
    class: 'block w-full h-full overflow-hidden',
  },
  imports: [
    CommonModule,
    TableActionRowComponent,
    UikitEmptyStateComponent,
    TableModule,
    ButtonModule,
    SkeletonModule,
    PaginatorModule,
    DrawerModule,
    PaginatorComponent,
    UikitCopyComponent,
    KeyValueComponent,
  ],
})
export class PageDataListComponent<I> {
  constructor(
    private host: ElementRef,
    private renderer: Renderer2,
  ) {}

  @Input({ required: true }) pageTitle!: string;
  @Input() addNewCtaLabel?: string;
  @Input({ required: true }) columns!: IColumn[];
  @Input({ required: true }) items!: I[];
  @Input({ required: true }) loading!: boolean;
  @Input() emptyPlaceholderTitle: string = 'موردی برای نمایش وجود ندارد';
  @Input() emptyPlaceholderDescription?: string = '';
  @Input() emptyPlaceholderCtaLabel?: string;
  @Input() totalRecords!: number;
  @Input() perPage?: number = 10;
  @Input() currentPage?: number = 1;
  @Input() showEdit: boolean = false;
  @Input() showDelete: boolean = false;
  @Input() showDetails: boolean = false;
  @Input() showAdd: boolean = false;
  @Input() showRefresh: boolean = true;
  @Input() isFiltered: boolean = false;
  @Input() fullHeight?: boolean = false;
  @Input() height: string = '';
  @Input() expandable?: boolean = false;
  @Input() expandableItemKey?: string = '';
  @Input() expandColumns?: Maybe<IColumn[]> = null;
  @Input() dataKey?: string = 'items';

  @ContentChild('filter', { static: true }) filter!: TemplateRef<any> | null;
  @ContentChild('caption', { static: true }) caption!: TemplateRef<any> | null;
  @ContentChild('moreActions', { static: true }) moreActions!: TemplateRef<any> | null;
  @ContentChild('expandableTemp', { static: false }) expandableTemp!: TemplateRef<any> | null;

  @Output() onEdit = new EventEmitter<I>();
  @Output() onDelete = new EventEmitter<I>();
  @Output() onDetails = new EventEmitter<I>();
  @Output() onAdd = new EventEmitter<void>();
  @Output() onChangePage = new EventEmitter<any>();
  @Output() onThumbnailClick = new EventEmitter<I>();
  @Output() onRefresh = new EventEmitter();

  filterDrawerVisible = signal<boolean>(false);
  expandedRows: { [key: string]: boolean } = {};

  ngOnInit() {
    if (this.height)
      this.renderer.setStyle(
        this.host.nativeElement,
        'height',
        this.fullHeight ? '100cqmin' : this.height,
      );
    // if (this.fullHeight) {
    // }
  }

  edit = (item: I) => {
    this.onEdit.emit(item);
  };

  remove = (item: I) => {
    this.onDelete.emit(item);
  };

  details = (item: I) => {
    this.onDetails.emit(item);
  };

  openAddForm = () => {
    this.onAdd.emit();
  };

  openFilter = () => {
    this.filterDrawerVisible.set(true);
  };

  closeFilter = () => {
    this.filterDrawerVisible.set(false);
  };

  onPage = ($event: any) => {
    this.onChangePage.emit($event);
  };

  openThumbnailModal = (item: I) => {
    // this.
  };

  get showPaginator() {
    return !!(this.totalRecords && this.perPage && this.totalRecords > this.perPage);
  }

  getPreviewClasses(item: Record<string, any>, column: IColumn): any {
    if (!item || !column || column.customDataModel) return '';
    try {
      const { field } = column;

      const data = item[String(field)];
      switch (column.type) {
        case 'date':
          if (column.dateOption?.expiredMode) {
            if (jalaliDiff(new Date(), data) > 0) {
              return 'text-error';
            }
          }
          return '';
        default:
          return;
      }
    } catch (e) {
      return '';
    }
  }

  getCell(item: Record<string, any>, column: IColumn): any {
    if (!item || !column) return '';
    try {
      let { field, type } = column;

      if (column.customDataModel) {
        return this.renderCustom(column, item);
      }

      let data = item[String(field)];
      if (column.type === 'nested') {
        const path = column.nestedOption?.path;
        if (!path) return '-';
        data = path
          .split('.')
          .reduce((obj, key) => (obj && obj[key] !== undefined ? obj[key] : null), item);
        type = column.nestedOption?.type || 'simple';
      }

      if (type) {
        switch (type) {
          case 'id':
            if (!data) return '-';
            return `${data.slice(0, 5)}...${data.slice(data.length - 5, data.length)}`;
          case 'date':
            if (!data) return '-';
            return formatJalali(data);
          case 'boolean':
            return data ? 'بله' : 'خیر';
          case 'price':
            return formatWithCurrency(data, false, 'ریال');
          default:
            break;
        }
      }
      if (data === undefined || data === null) {
        return '-';
      }
      if (typeof data === 'object') {
        return data.title || '-';
      }
      return data || '-';
    } catch (e) {
      return '-';
    }
  }

  getTemplate(col: IColumn): TemplateRef<any> | null {
    const v = col.customDataModel;
    return v instanceof TemplateRef ? (v as TemplateRef<any>) : null;
  }

  renderCustom(column: IColumn, item: any): any {
    const v = column.customDataModel;

    if (!v) {
      return null;
    }
    if (typeof v === 'function') {
      try {
        return (v as (item: any) => any)(item);
      } catch {
        return '-';
      }
    }
    if (typeof v === 'string') return v;
    return null;
  }

  actionsCount = computed(() => {
    let totalCount = 0;
    if (this.showEdit) totalCount += 1;
    if (this.showDelete) totalCount += 1;
    if (this.showDetails) totalCount += 1;
    return totalCount;
  });

  refresh() {
    this.onRefresh.emit();
  }
}
