/**
 * @aurora-catalyst-generated
 * @source cliter/iam/permission.aurora.yaml
 */
import {
  ChangeDetectionStrategy,
  Component,
  computed,
  inject,
  input,
  signal,
  viewChild,
  type OnInit,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import {
  ColumnToggle,
  DataTable,
  DEFAULT_PAGE_SIZE,
  getExportableColumns,
  getFilterableColumns,
  getRelationIncludes,
  getSearchableColumnIds,
  getToggleableColumns,
  HeadSelection,
  listContainerClass,
  RowSelection,
  TableExport,
  TableFilters,
  TablePagination,
  TableSearch,
  useAggregateShell,
  useBreadcrumbs,
  usePaginatedDataTable,
  type DataTableColumnDef,
  type DataTableData,
} from '@aurora';
import { provideTranslocoScope, TranslocoDirective, TranslocoService } from '@jsverse/transloco';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucidePlus, lucideShield } from '@ng-icons/lucide';
import { toast } from '@spartan-ng/brain/sonner';
import { HlmAlertDialog, HlmAlertDialogImports } from '@spartan-ng/helm/alert-dialog';
import { HlmButtonImports } from '@spartan-ng/helm/button';
import { HlmDialogImports } from '@spartan-ng/helm/dialog';
import { HlmIconImports } from '@spartan-ng/helm/icon';
import { HlmSpinnerImports } from '@spartan-ng/helm/spinner';
import { type IamBoundedContext, type IamPermission } from '@src/src/app/aurora.types';
import { flexRenderComponent } from '@tanstack/angular-table';
import { lastValueFrom } from 'rxjs';
import { PERMISSION_DETAIL_CONFIG } from '../data-access/permission.detail-config';
import { PERMISSION_LIST_CONFIG } from '../data-access/permission.list-config';
import { getPermissionEmbedColumns, getPermissionStandaloneColumns } from '../permission.columns';
import { PermissionFormEmbedComponent } from './permission-form-embed.component';
import { PermissionFormComponent } from './permission-form.component';
import { PermissionListActionsCell } from './permission-list-actions-cell.component';

@Component({
  selector: 'au-permission-list',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    TranslocoDirective,
    NgIcon,
    ColumnToggle,
    DataTable,
    TableExport,
    TableFilters,
    TablePagination,
    TableSearch,
    HlmAlertDialogImports,
    HlmButtonImports,
    HlmIconImports,
    HlmDialogImports,
    HlmSpinnerImports,
    PermissionFormComponent,
    PermissionFormEmbedComponent,
  ],
  providers: [provideIcons({ lucidePlus, lucideShield }), provideTranslocoScope('iam')],
  host: { class: 'block' },
  template: `
    <div
      *transloco="let t; scope: 'iam'"
      [class]="containerClass()"
    >
      @if (mode() === 'standalone') {
        <div class="mb-2 flex items-center justify-between">
          <h1 class="flex items-center gap-2 text-2xl font-bold tracking-tight">
            <ng-icon
              name="lucideShield"
              class="text-[1em]"
            />
            {{ t('iam.permission.Title') }}
          </h1>
        </div>
      }

      <!-- Toolbar -->
      <div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
        <au-table-search
          [placeholder]="t('FilterPlaceholder')"
          [value]="paginated.search.value()"
          (search)="paginated.setSearch($event)"
        />
        <div class="flex items-center gap-2">
          <button
            hlmBtn
            size="sm"
            (click)="onNew()"
          >
            <ng-icon
              name="lucidePlus"
              class="sm:mr-1"
              hlm
              size="sm"
            />
            <span class="hidden sm:inline">
              {{ t('New.M') }} {{ t('iam.permission.Permission') }}
            </span>
          </button>
          <au-table-filters
            [columns]="filterableColumns()"
            (filtersChange)="paginated.setFilters($event)"
          />
          <au-column-toggle
            [table]="paginated.table"
            [columns]="toggleableColumns()"
          />
          <au-table-export
            [table]="paginated.table"
            [columns]="exportableColumns()"
            filename="permissions"
          />
        </div>
      </div>

      <!-- Table -->
      <au-data-table
        [table]="paginated.table"
        [loading]="paginated.loading()"
        [emptyMessage]="t('iam.permission.NoPermissionsFound')"
      />

      <!-- Pagination -->
      <au-table-pagination [table]="paginated.table" />

      <!-- Create / edit dialog -->
      <hlm-dialog
        [state]="dialogOpen() ? 'open' : 'closed'"
        (closed)="dialogOpen.set(false)"
      >
        <hlm-dialog-content
          *hlmDialogPortal="let ctx"
          class="max-h-[90vh] overflow-y-auto sm:max-w-2xl"
        >
          <hlm-dialog-header>
            <h3 hlmDialogTitle>
              {{ dialogMode() === 'new' ? t('Create') : t('Edit') }}
              {{ t('iam.permission.Permission') }}
            </h3>
            <p hlmDialogDescription>{{ t('iam.permission.PermissionDetailsDescription') }}</p>
          </hlm-dialog-header>
          @if (mode() === 'embed') {
            <au-permission-form-embed
              #form
              [initial]="dialogInitial()"
              [mode]="dialogMode()"
              [parentValue]="parentFilter()?.value ?? ''"
              (save)="onDialogSave($event)"
              (cancel)="ctx.close()"
            />
            <hlm-dialog-footer>
              <button
                type="button"
                hlmBtn
                variant="outline"
                (click)="ctx.close()"
              >
                {{ t('Cancel') }}
              </button>
              <button
                type="button"
                [disabled]="form.signalForm.invalid || form.signalForm.pristine || shell.loading()"
                hlmBtn
                (click)="form.submit()"
              >
                @if (shell.loading()) {
                  <hlm-spinner class="text-sm" />
                }
                {{ dialogMode() === 'new' ? t('Create') : t('Save') }}
              </button>
            </hlm-dialog-footer>
          } @else {
            <au-permission-form
              #form
              [initial]="dialogInitial()"
              [mode]="dialogMode()"
              [boundedContextOptions]="boundedContextOptions()"
              (save)="onDialogSave($event)"
              (cancel)="ctx.close()"
            />
            <hlm-dialog-footer>
              <button
                type="button"
                hlmBtn
                variant="outline"
                (click)="ctx.close()"
              >
                {{ t('Cancel') }}
              </button>
              <button
                type="button"
                [disabled]="form.signalForm.invalid || form.signalForm.pristine || shell.loading()"
                hlmBtn
                (click)="form.submit()"
              >
                @if (shell.loading()) {
                  <hlm-spinner class="text-sm" />
                }
                {{ dialogMode() === 'new' ? t('Create') : t('Save') }}
              </button>
            </hlm-dialog-footer>
          }
        </hlm-dialog-content>
      </hlm-dialog>

      <!-- Delete confirmation dialog -->
      <hlm-alert-dialog>
        <hlm-alert-dialog-content *hlmAlertDialogPortal="let ctx">
          <hlm-alert-dialog-header>
            <h2 hlmAlertDialogTitle>{{ t('Delete') }} {{ t('iam.permission.Permission') }}</h2>
            <p hlmAlertDialogDescription>
              {{ t('DeleteConfirmation', { name: permissionToDelete()?.name }) }}
            </p>
          </hlm-alert-dialog-header>
          <hlm-alert-dialog-footer>
            <button
              hlmAlertDialogCancel
              (click)="ctx.close()"
            >
              {{ t('Cancel') }}
            </button>
            <button
              hlmAlertDialogAction
              (click)="onConfirmDelete(); ctx.close()"
            >
              {{ t('Delete') }}
            </button>
          </hlm-alert-dialog-footer>
        </hlm-alert-dialog-content>
      </hlm-alert-dialog>
    </div>
  `,
})
export default class PermissionListComponent implements OnInit {
  // inputs
  readonly mode = input<'standalone' | 'embed'>('standalone');
  readonly parentFilter = input<{ field: string; value: string } | null>(null);

  // injections
  private readonly route = inject(ActivatedRoute);
  private readonly transloco = inject(TranslocoService);

  // widgets
  private readonly deleteDialog = viewChild(HlmAlertDialog);

  // layout
  protected readonly containerClass = computed(() => listContainerClass(this.mode()));

  // state
  private readonly dataResolved =
    this.mode() === 'embed'
      ? null
      : (this.route.snapshot.data['pagination'] as {
          pagination: DataTableData<IamPermission>;
          boundedContextOptions: IamBoundedContext[];
        });
  readonly permissionToDelete = signal<IamPermission | null>(null);
  readonly dialogOpen = signal(false);
  readonly dialogMode = signal<'new' | 'edit'>('new');
  readonly dialogInitial = signal<IamPermission | null>(null);
  readonly boundedContextOptions = signal<IamBoundedContext[]>(
    this.dataResolved?.boundedContextOptions ?? [],
  );

  // columns
  // Mode is read at construction time — Aurora does not switch modes dynamically.
  private readonly baseColumns =
    this.mode() === 'embed'
      ? getPermissionEmbedColumns({ translator: this.transloco })
      : getPermissionStandaloneColumns({ translator: this.transloco });
  protected readonly filterableColumns = () => getFilterableColumns(this.baseColumns);
  protected readonly exportableColumns = () => getExportableColumns(this.baseColumns);
  protected readonly toggleableColumns = () => getToggleableColumns(this.baseColumns);
  private readonly searchColumns = getSearchableColumnIds(this.baseColumns);
  private readonly relationIncludes = getRelationIncludes(this.baseColumns);
  protected readonly columns: DataTableColumnDef<IamPermission>[] = [
    {
      id: 'actions',
      sticky: 'left',
      size: 50,
      enableHiding: false,
      enableSorting: false,
      header: '',
      cell: () =>
        flexRenderComponent(PermissionListActionsCell, {
          inputs: {
            onRequestEdit: (permission: IamPermission) => this.onEdit(permission),
            onRequestDelete: (permission: IamPermission) => this.onDelete(permission),
          },
        }),
    },
    {
      id: 'select',
      sticky: 'left',
      size: 40,
      enableHiding: false,
      enableSorting: false,
      header: () => flexRenderComponent(HeadSelection),
      cell: () => flexRenderComponent(RowSelection),
    },
    ...this.baseColumns,
  ];

  // composables
  private readonly breadcrumb = useBreadcrumbs([{ translation: 'navigation.Permissions' }]);
  readonly shell = useAggregateShell<IamPermission>({
    listConfig: PERMISSION_LIST_CONFIG,
    detailConfig: PERMISSION_DETAIL_CONFIG,
  });
  protected readonly paginated = usePaginatedDataTable<IamPermission>({
    paginate: (input) => this.shell.list.paginate(input),
    columns: this.columns,
    searchableColumnIds: this.searchColumns,
    defaultPageSize: DEFAULT_PAGE_SIZE,
    constraint: () => {
      const pf = this.parentFilter();
      return pf ? { [pf.field]: pf.value } : null;
    },
    relationIncludes: () => (this.relationIncludes.length > 0 ? this.relationIncludes : []),
  });

  constructor() {
    if (this.dataResolved?.pagination) {
      this.paginated.seed(this.dataResolved.pagination);
    }
  }

  // ─── methods ────────────────────────────────────────────────

  ngOnInit(): void {
    // Embed mode has no route resolver — refetch on init.
    if (this.mode() === 'embed') {
      void this.paginated.refetch();
    }
  }

  onNew() {
    this.dialogMode.set('new');
    this.dialogInitial.set(null);
    this.dialogOpen.set(true);
  }

  async onEdit(permission: IamPermission) {
    const obj = await this.shell.fetchForEdit(permission.id);
    this.dialogInitial.set(obj);
    this.dialogMode.set('edit');
    this.dialogOpen.set(true);
  }

  async onDialogSave(value: IamPermission) {
    try {
      await this.shell.save(value, this.dialogMode());
      const verb = this.dialogMode() === 'new' ? 'Created.M' : 'Saved.M';
      toast.success(
        `${this.transloco.translate(verb)} ${this.transloco.translate('Successfully')}`,
      );
      this.dialogOpen.set(false);
      await this.paginated.refetch();
    } catch {
      // error displayed by GRAPHQL_ERROR_HANDLER
    }
  }

  onDelete(permission: IamPermission) {
    this.permissionToDelete.set(permission);
    this.deleteDialog()?.open();
  }

  async onConfirmDelete() {
    const permission = this.permissionToDelete();
    if (!permission) return;

    try {
      await lastValueFrom(this.shell.list.deleteById(permission.id));
      toast.success(
        `${this.transloco.translate('Deleted.M')} ${this.transloco.translate('Successfully')}`,
      );
      await this.paginated.refetch();
    } catch {
      // error displayed by GRAPHQL_ERROR_HANDLER
    } finally {
      this.permissionToDelete.set(null);
    }
  }
}
