import {Component, ElementRef, HostListener, Input, OnInit, ViewChildren} from '@angular/core';
import HostRecord from '../../structures/HostRecord';
import {ActivatedRoute, Router} from '@angular/router';
import {AlertController, LoadingController, ModalController, PopoverController} from '@ionic/angular';
import {NodePickerComponent} from '../../components/editor/node-picker/node-picker.component';
import {HostOptionsComponent} from '../../components/editor/host-options/host-options.component';
import {EditorService} from '../../service/editor.service';
import {NodeTypeIcons} from '../../structures/node-types';
import {OptionMenuComponent} from '../../components/option-menu/option-menu.component';
import {VersionModalComponent} from '../../components/version-modal/version-modal.component';
import {debug} from '../../utility';
import {DatabaseLinkComponent} from '../../components/editor/forms/database-link.component';

@Component({
  selector: 'app-editor',
  templateUrl: './editor.page.html',
  styleUrls: ['./editor.page.scss'],
})
export class EditorPage implements OnInit {
  public typeIcons = NodeTypeIcons;
  @Input() pageId: string;
  @Input() isFilloutMode = false;
  @Input() hosted = false;
  @Input() version?: number;

  @ViewChildren('nodeContainer') nodeContainers;
  @ViewChildren('nodeContainer', { read: ElementRef }) nodeElements;

  public pageType?: string;

  protected scrollToNodeId?: string;

  @Input()
  set readonly(val: boolean) {
    this.editorService.forceReadonly = val;
  }

  get readonly() {
    return this.editorService.forceReadonly;
  }

  constructor(
    protected route: ActivatedRoute,
    protected router: Router,
    protected loader: LoadingController,
    protected popover: PopoverController,
    protected alerts: AlertController,
    protected modals: ModalController,
    public readonly editorService: EditorService,
  ) {
    debug('Constructed editor page.');

    this.route.params.subscribe(params => {
      this.pageId = params.id;
      debug('Got page ID from route:', this.pageId, params);

      if ( params.node_id ) {
        debug('Scroll to node ID:', params.node_id);
        this.scrollToNodeId = params.node_id;
      }
    });

    this.editorService = editorService.getEditor();
  }

  ngOnInit() {}

  async ionViewDidEnter() {
    debug('Ion view did enter editor page.');

    if ( this.pageId ) {
      await this.editorService.startEditing(this.pageId, this.version);
    } else if ( !this.hosted ) {
      await this.router.navigate(['/home']);
    }

    setTimeout(() => {
      if ( this.scrollToNodeId ) {
        debug('Scrolling to node.');

        const nodes = this.nodeContainers.toArray();
        const elements = this.nodeElements.toArray();
        debug('Nodes', {nodes, elements});

        nodes.forEach((node, i) =>  {
          if ( node.nodeId === this.scrollToNodeId ) {
            elements[i].nativeElement.scrollIntoView();
            node.performUIActivation();
          }
        });
      }
    }, 150);
  }

  @HostListener('document:keydown.control.s', ['$event'])
  onManualSave(event) {
    event.preventDefault();
    this.editorService.save();
  }

  async onOptionsClick(event: MouseEvent, node: HostRecord) {
    if ( !this.editorService.canEdit() ) {
      return;
    }

    const popover = await this.popover.create({
      component: HostOptionsComponent,
      event,
      componentProps: {
        editor: this,
        index: this.editorService.immutableNodes.indexOf(node),
        event,
        hostRecord: node,
      }
    });

    popover.onDidDismiss().then(result => {
      const { event: dismissEvent , value } = result.data;
      if ( value === 'delete_node' ) {
        this.alerts.create({
          header: 'Delete node?',
          message: 'Are you sure you want to delete this node? Its contents will be unrecoverable.',
          buttons: [
            {
              text: 'Keep It',
              role: 'cancel',
            },
            {
              text: 'Delete It',
              role: 'ok',
              handler: () => {
                this.editorService.deleteNode(node.UUID);
              }
            }
          ],
        }).then(alert => alert.present());
      } else if ( value === 'move_up' ) {
        this.editorService.moveNode(node, 'up');
      } else if ( value === 'move_down' ) {
        this.editorService.moveNode(node, 'down');
      } else if ( value === 'add_before' ) {
        this.onAddClick(event, 'before', node.UUID);
      } else if ( value === 'add_after' ) {
        this.onAddClick(event, 'after', node.UUID);
      }
    });

    await popover.present();
  }

  async onAddClick(event: MouseEvent, position?: 'before' | 'after', positionNodeId?: string) {
    if ( !this.editorService.canEdit() ) {
      return;
    }

    const popover = await this.popover.create({
      component: NodePickerComponent,
      event,
      componentProps: {
        formMode: this.editorService.currentPageType === 'form',
      },
    });

    popover.onDidDismiss().then(result => {
      if ( !result.data ) {
        return;
      }

      this.editorService.addNode(result.data, position, positionNodeId);
    });

    await popover.present();
  }

  async onPageMenuClick(event: MouseEvent) {
    debug('Page type: ', this.pageType)
    const popover = await this.popover.create({
      event,
      component: OptionMenuComponent,
      componentProps: {
        menuItems: [
          {
            name: 'Versions',
            icon: 'fa fa-history',
            value: 'view-versions',
            title: 'View other versions of this page',
          },
          ...(this.editorService.currentPageType === 'form' ? [
            {
              name: 'Link to Database',
              icon: NodeTypeIcons.db,
              value: 'link-to-db',
              title: 'Configure the database where submissions of this form will be stored',
            },
          ] : []),
        ],
      },
    });

    popover.onDidDismiss().then(async value => {
      const { data } = value;

      if ( data === 'view-versions' ) {
        await this.showVersionModal();
      } else if ( data === 'link-to-db' ) {
        await this.showFormDatabaseLinkModal();
      }
    });

    await popover.present();
  }

  async showFormDatabaseLinkModal() {
    const modal = await this.modals.create({
      component: DatabaseLinkComponent,
      componentProps: {
        pageId: this.pageId,
        editorUUID: this.editorService.instanceUUID,
      },
      cssClass: 'modal-med',
    });

    modal.onDidDismiss().then(data => {
      debug('Database link closed', data);
    });

    const modalState = {
      modal : true,
      desc : 'Link form to database'
    };

    history.pushState(modalState, null);

    await modal.present();
  }

  async showVersionModal() {
    const modal = await this.modals.create({
      component: VersionModalComponent,
      componentProps: {
        pageId: this.pageId,
      },
      cssClass: 'modal-big',
    });

    modal.onDidDismiss().then(data => {
      if ( data.data ) {
        this.editorService.startEditing(this.pageId);
      }
    });

    const modalState = {
      modal : true,
      desc : 'Page versions'
    };

    history.pushState(modalState, null);

    await modal.present();
  }
}
