import {
  AsyncPipe,
  NgIf,
} from '@angular/common';
import {
  ChangeDetectorRef,
  Component,
  Input,
  OnDestroy,
  ViewChild,
} from '@angular/core';
import { FormsModule } from '@angular/forms';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core';
import { UiSwitchModule } from 'ngx-ui-switch';
import {
  concatMap,
  Observable,
  shareReplay,
} from 'rxjs';
import {
  map,
  take,
} from 'rxjs/operators';

import { BulkAccessConfigDataService } from '../../core/config/bulk-access-config-data.service';
import { BulkAccessConditionOptions } from '../../core/config/models/bulk-access-condition-options.model';
import { RemoteData } from '../../core/data/remote-data';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { Item } from '../../core/shared/item.model';
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import { AlertComponent } from '../alert/alert.component';
import { AlertType } from '../alert/alert-type';
import { BtnDisabledDirective } from '../btn-disabled.directive';
import { SelectableListService } from '../object-list/selectable-list/selectable-list.service';
import { AccessControlArrayFormComponent } from './access-control-array-form/access-control-array-form.component';
import { createAccessControlInitialFormState } from './access-control-form-container-intial-state';
import { BulkAccessControlService } from './bulk-access-control.service';
import {
  ITEM_ACCESS_CONTROL_SELECT_BITSTREAMS_LIST_ID,
  ItemAccessControlSelectBitstreamsModalComponent,
} from './item-access-control-select-bitstreams-modal/item-access-control-select-bitstreams-modal.component';

@Component({
  selector: 'ds-access-control-form-container',
  templateUrl: './access-control-form-container.component.html',
  styleUrls: ['./access-control-form-container.component.scss'],
  exportAs: 'dsAccessControlForm',
  standalone: true,
  imports: [NgIf, AlertComponent, UiSwitchModule, FormsModule, AccessControlArrayFormComponent, AsyncPipe, TranslateModule, BtnDisabledDirective],
})
export class AccessControlFormContainerComponent<T extends DSpaceObject> implements OnDestroy {

  /**
   * Will be used to determine if we need to show the limit changes to specific bitstreams radio buttons
   */
  @Input() showLimitToSpecificBitstreams = false;

  /**
   * The title message of the access control form (translate key)
   */
  @Input() titleMessage = '';

  /**
   * The item to which the access control form applies
   */
  @Input() itemRD: RemoteData<T>;

  /**
   * Whether to show the submit and cancel button
   * We want to hide these buttons when the form is
   * used in an accordion, and we want to show buttons somewhere else
   */
  @Input() showSubmit = true;

  @ViewChild('bitstreamAccessCmp', { static: true }) bitstreamAccessCmp: AccessControlArrayFormComponent;
  @ViewChild('itemAccessCmp', { static: true }) itemAccessCmp: AccessControlArrayFormComponent;

  readonly AlertType = AlertType;

  constructor(
    private bulkAccessConfigService: BulkAccessConfigDataService,
    private bulkAccessControlService: BulkAccessControlService,
    public selectableListService: SelectableListService,
    protected modalService: NgbModal,
    private cdr: ChangeDetectorRef,
  ) {}

  state = createAccessControlInitialFormState();

  dropdownData$: Observable<BulkAccessConditionOptions> = this.bulkAccessConfigService.findByName('default').pipe(
    getFirstCompletedRemoteData(),
    map((configRD: RemoteData<BulkAccessConditionOptions>) => configRD.hasSucceeded ? configRD.payload : null),
    shareReplay({ refCount: false, bufferSize: 1 }),
  );

  /**
   * Will be used from a parent component to read the value of the form
   */
  getFormValue() {
    console.log({
      bitstream: this.bitstreamAccessCmp.getValue(),
      item: this.itemAccessCmp.getValue(),
      state: this.state,
    });
    return {
      bitstream: this.bitstreamAccessCmp.getValue(),
      item: this.itemAccessCmp.getValue(),
      state: this.state,
    };
  }

  /**
   * Reset the form to its initial state
   * This will also reset the state of the child components (bitstream and item access)
   */
  reset() {
    this.bitstreamAccessCmp.reset();
    this.itemAccessCmp.reset();
    this.state = createAccessControlInitialFormState();
  }

  /**
   * Submit the form
   * This will create a payload file and execute the script
   */
  submit() {
    const bitstreamAccess = this.bitstreamAccessCmp.getValue();
    const itemAccess = this.itemAccessCmp.getValue();

    const { file } = this.bulkAccessControlService.createPayloadFile({
      bitstreamAccess,
      itemAccess,
      state: this.state,
    });

    this.bulkAccessControlService.executeScript(
      [ this.itemRD.payload.uuid ],
      file,
    ).pipe(take(1)).subscribe((res) => {
      console.log('success', res);
    });
  }

  /**
   * Handle the status change of the access control form (item or bitstream)
   * This will enable/disable the access control form for the item or bitstream
   * @param type The type of the access control form (item or bitstream)
   * @param active boolean indicating whether the access control form should be enabled or disabled
   */
  handleStatusChange(type: 'item' | 'bitstream', active: boolean) {
    if (type === 'bitstream') {
      active ? this.bitstreamAccessCmp.enable() : this.bitstreamAccessCmp.disable();
    } else if (type === 'item') {
      active ? this.itemAccessCmp.enable() : this.itemAccessCmp.disable();
    }
  }

  /**
   * Open the modal to select bitstreams for which to change the access control
   * This will open the modal and pass the currently selected bitstreams
   * @param item The item for which to change the access control
   */
  openSelectBitstreamsModal(item: Item) {
    const ref = this.modalService.open(ItemAccessControlSelectBitstreamsModalComponent);
    ref.componentInstance.selectedBitstreams = this.state.bitstream.selectedBitstreams;
    ref.componentInstance.item = item;

    ref.closed.pipe(
      concatMap(() => this.selectableListService.getSelectableList(ITEM_ACCESS_CONTROL_SELECT_BITSTREAMS_LIST_ID)),
      take(1),
    ).subscribe((list) => {
      this.state.bitstream.selectedBitstreams = list?.selection || [];
      this.cdr.detectChanges();
    });
  }

  ngOnDestroy(): void {
    this.selectableListService.deselectAll(ITEM_ACCESS_CONTROL_SELECT_BITSTREAMS_LIST_ID);
  }

}