import { Component, inject, signal } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { RouterLink } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar';
import { AgGridAngular } from 'ag-grid-angular';
import type {
  ColDef,
  GetRowIdParams,
  GridApi,
  GridReadyEvent,
  IDatasource,
  IGetRowsParams,
} from 'ag-grid-community';
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { AuthStore } from '../../core/auth/auth-store';
import { CashboxExportApi } from '../../core/team/cashbox-export-api';
import { RecurringTransactionApi } from '../../core/team/recurring-transaction-api';
import { LogsApi } from '../../core/logs/logs-api';
import { LogEntry, LogLevel, LogQuery } from '../../models/log.model';
import '../../shared/ag-grid/ag-grid-modules';
import { teamwalletGridTheme } from '../../shared/ag-grid/ag-grid-theme';

const LOG_LEVEL_OPTIONS: { value: string; label: string }[] = [
  { value: '', label: 'Alle Level' },
  { value: 'FATAL', label: 'FATAL' },
  { value: 'ERROR', label: 'ERROR' },
  { value: 'WARN', label: 'WARN' },
  { value: 'INFO', label: 'INFO' },
  { value: 'DEBUG', label: 'DEBUG' },
  { value: 'TRACE', label: 'TRACE' },
];

// Kept in sync manually with LOGEVENT_VALUES (myteamwallet_backend/src/database/logging/model/logging-event.type.ts),
// the same way transaction type labels are already duplicated on the frontend elsewhere in this app.
const LOG_EVENT_OPTIONS: { value: string; label: string }[] = [
  { value: '', label: 'Alle Events' },
  { value: 'user_create', label: 'user_create' },
  { value: 'application_start', label: 'application_start' },
  { value: 'transaction_create', label: 'transaction_create' },
  { value: 'team_transaction_create', label: 'team_transaction_create' },
  { value: 'team_transaction_get', label: 'team_transaction_get' },
  { value: 'user_login_success', label: 'user_login_success' },
  { value: 'user_login_fail', label: 'user_login_fail' },
  { value: 'user_token_verification_success', label: 'user_token_verification_success' },
  { value: 'user_token_verification_fail', label: 'user_token_verification_fail' },
  { value: 'user_invite_link_create', label: 'user_invite_link_create' },
  { value: 'user_invite_link_validate', label: 'user_invite_link_validate' },
  { value: 'user_invite_link_validate_fail', label: 'user_invite_link_validate_fail' },
  { value: 'transaction_create_fail', label: 'transaction_create_fail' },
  { value: 'transaction_reverse', label: 'transaction_reverse' },
  { value: 'player_creation', label: 'player_creation' },
  { value: 'admin_user_profile_update', label: 'admin_user_profile_update' },
  { value: 'admin_user_role_update', label: 'admin_user_role_update' },
  { value: 'admin_user_status_update', label: 'admin_user_status_update' },
  { value: 'admin_player_assign', label: 'admin_player_assign' },
  { value: 'admin_player_unlink', label: 'admin_player_unlink' },
  { value: 'player_active_update', label: 'player_active_update' },
  { value: 'player_team_role_update', label: 'player_team_role_update' },
  { value: 'penalty_catalog_create', label: 'penalty_catalog_create' },
  { value: 'penalty_catalog_update', label: 'penalty_catalog_update' },
  { value: 'penalty_catalog_delete', label: 'penalty_catalog_delete' },
  { value: 'team_create', label: 'team_create' },
  { value: 'team_permissions_update', label: 'team_permissions_update' },
  { value: 'scheduled_recurring_transaction_check_start', label: 'scheduled_recurring_transaction_check_start' },
  {
    value: 'scheduled_recurring_transaction_check_finished',
    label: 'scheduled_recurring_transaction_check_finished',
  },
  { value: 'recurring_transaction_create', label: 'recurring_transaction_create' },
  { value: 'recurring_transaction_update', label: 'recurring_transaction_update' },
  { value: 'recurring_transaction_delete', label: 'recurring_transaction_delete' },
  { value: 'recurring_transaction_run', label: 'recurring_transaction_run' },
  { value: 'cashbox_export_download', label: 'cashbox_export_download' },
  { value: 'cashbox_export_subscription_update', label: 'cashbox_export_subscription_update' },
  { value: 'cashbox_export_subscription_run', label: 'cashbox_export_subscription_run' },
  { value: 'cashbox_export_subscription_run_fail', label: 'cashbox_export_subscription_run_fail' },
  { value: 'log_retention_cleanup_run', label: 'log_retention_cleanup_run' },
];

@Component({
  selector: 'app-logs',
  imports: [
    RouterLink,
    MatButtonModule,
    MatFormFieldModule,
    MatIconModule,
    MatInputModule,
    MatSelectModule,
    AgGridAngular,
  ],
  templateUrl: './logs.html',
  styleUrl: './logs.scss',
})
export class Logs {
  private readonly authStore = inject(AuthStore);
  private readonly logsApi = inject(LogsApi);
  private readonly cashboxExportApi = inject(CashboxExportApi);
  private readonly recurringTransactionApi = inject(RecurringTransactionApi);
  private readonly snackBar = inject(MatSnackBar);

  protected readonly isAdmin = this.authStore.isGlobalAdmin;
  protected readonly gridTheme = teamwalletGridTheme;
  protected readonly levelOptions = LOG_LEVEL_OPTIONS;
  protected readonly eventOptions = LOG_EVENT_OPTIONS;

  protected readonly levelFilter = signal('');
  protected readonly eventFilter = signal('');
  protected readonly fromFilter = signal('');
  protected readonly toFilter = signal('');
  protected readonly search = signal('');
  protected readonly cashboxRunning = signal(false);
  protected readonly recurringRunning = signal(false);

  private readonly searchInput$ = new Subject<string>();
  private gridApi?: GridApi<LogEntry>;

  protected readonly columnDefs: ColDef<LogEntry>[] = [
    {
      headerName: 'Zeitpunkt',
      field: 'createdAt',
      width: 170,
      valueFormatter: (params) =>
        params.value
          ? new Intl.DateTimeFormat('de-DE', { dateStyle: 'short', timeStyle: 'medium' }).format(
              new Date(params.value),
            )
          : '',
    },
    {
      headerName: 'Level',
      field: 'level',
      width: 100,
      cellClass: (params) => `log-level log-level--${(params.value ?? '').toLowerCase()}`,
    },
    { headerName: 'Event', field: 'event', minWidth: 220, flex: 1 },
    {
      headerName: 'Wer',
      field: 'userId',
      width: 90,
      valueFormatter: (params) => (params.value === -1 ? 'System' : `#${params.value}`),
    },
    { headerName: 'Details', field: 'details', minWidth: 260, flex: 2 },
    {
      headerName: 'Dauer',
      field: 'duration',
      width: 90,
      valueFormatter: (params) => (params.value != null ? `${params.value} ms` : ''),
    },
  ];

  protected readonly getRowId = (params: GetRowIdParams<LogEntry>) => String(params.data.id);

  constructor() {
    this.searchInput$.pipe(debounceTime(300), takeUntilDestroyed()).subscribe((value) => {
      this.search.set(value);
      this.reloadLogs();
    });
  }

  protected onGridReady(event: GridReadyEvent<LogEntry>): void {
    this.gridApi = event.api;
    this.reloadLogs();
  }

  protected onFilterChange(): void {
    this.reloadLogs();
  }

  protected onSearchInput(value: string): void {
    this.searchInput$.next(value);
  }

  private reloadLogs(): void {
    this.gridApi?.setGridOption('datasource', this.buildLogsDatasource());
  }

  private buildLogsDatasource(): IDatasource {
    return {
      getRows: (params: IGetRowsParams) => {
        const limit = Math.max(1, params.endRow - params.startRow);
        const page = Math.floor(params.startRow / limit) + 1;
        const query: LogQuery = {
          page,
          limit,
          ...(this.levelFilter() ? { level: this.levelFilter() as LogLevel } : {}),
          ...(this.eventFilter() ? { event: this.eventFilter() } : {}),
          ...(this.fromFilter() ? { from: this.fromFilter() } : {}),
          ...(this.toFilter() ? { to: this.toFilter() } : {}),
          ...(this.search().trim() ? { search: this.search().trim() } : {}),
        };

        this.logsApi.loadLogs(query).subscribe({
          next: (result) => params.successCallback(result.data, result.total),
          error: () => params.failCallback(),
        });
      },
    };
  }

  protected triggerCashboxExportRun(): void {
    if (this.cashboxRunning()) return;
    this.cashboxRunning.set(true);
    this.cashboxExportApi.triggerRunNow().subscribe({
      next: () => {
        this.cashboxRunning.set(false);
        this.snackBar.open('Cashbox-Export wurde ausgeführt.', undefined, { duration: 4000 });
        this.reloadLogs();
      },
      error: () => {
        this.cashboxRunning.set(false);
        this.snackBar.open('Cashbox-Export konnte nicht ausgeführt werden.', undefined, { duration: 5000 });
      },
    });
  }

  protected triggerRecurringTransactionsRun(): void {
    if (this.recurringRunning()) return;
    this.recurringRunning.set(true);
    this.recurringTransactionApi.triggerRunNow().subscribe({
      next: () => {
        this.recurringRunning.set(false);
        this.snackBar.open('Wiederkehrende Buchungen wurden geprüft.', undefined, { duration: 4000 });
        this.reloadLogs();
      },
      error: () => {
        this.recurringRunning.set(false);
        this.snackBar.open(
          'Wiederkehrende Buchungen konnten nicht geprüft werden.',
          undefined,
          { duration: 5000 },
        );
      },
    });
  }
}
