import {
  Component, EventEmitter, Input,
  Output, OnChanges, SimpleChanges
} from '@angular/core';
import { ProbeHost } from '@overflow/commons-typescript/model/probe';
import * as CIDR from 'ip-cidr';
import * as ipRangeCheck from 'ip-range-check';
import { DiscoverPort, DiscoverService, DiscoverZone } from '@overflow/commons-typescript/model/discovery';
import { Checkbox } from 'primeng/primeng';

@Component({
  selector: 'of-discovery-search-config',
  templateUrl: './search-config.component.html',
})
export class SearchConfigComponent implements OnChanges {

  @Input() probeHost: ProbeHost;
  @Output() requestDiscovery = new EventEmitter<DiscoverZone>();

  ipVer: string;
  startIP: string;
  endIP: string;
  startPort: string;
  endPort: string;
  includeServices = [];

  hostChecked = true;
  portChecked = true;
  serviceChecked = true;
  tcpChecked = true;
  udpChecked = true;

  validation = false;
  ipErrMsg: string;
  portErrMsg: string;

  constructor(
  ) {
  }

  ngOnChanges(changes: SimpleChanges): void {
    this.initByProbe();
    this.validation = true;
  }

  initByProbe() {
    const cidr = new CIDR(this.probeHost.probe.cidr);
    if (!cidr.isValid()) {
      return;
    }
    this.ipVer = 'ipv4';
    this.startIP = cidr.addressStart.address;
    this.endIP = cidr.addressEnd.address;
    this.startPort = '1';
    this.endPort = '1024';

    // TODO: Initialize services
  }

  onRequestDiscovery() {
    let discoverPort: DiscoverPort = null;
    let discoverService: DiscoverService = null;

    if (this.serviceChecked) {
      const services = new Array();
      for (const service of this.includeServices) {
        services.push(service.description);
      }
      discoverService = {
        includeServices: services,
      };
    }
    if (this.portChecked) {
      discoverPort = {
        firstScanRange: Number(this.startPort),
        lastScanRange: Number(this.endPort),
        includeTCP: this.tcpChecked,
        includeUDP: this.udpChecked,
        excludePorts: null,
        discoverService: discoverService
      };
    }
    const discoverZone: DiscoverZone = {
      discoverHost: {
        firstScanRangev4: this.startIP,
        lastScanRangev4: this.endIP,
        discoverPort: discoverPort
      },
    };

    this.requestDiscovery.emit(discoverZone);
  }

  onPortCheckChange(serviceCheckbox: Checkbox, checked: boolean) {
    if (!checked) {
      serviceCheckbox.checked = false;
      this.serviceChecked = false;
    }
  }

  onServiceCheckChange(portCheckbox: Checkbox, checked: boolean) {
    if (checked) {
      portCheckbox.checked = true;
      this.portChecked = true;
    }
  }

  onInputIP(e, idx: number) {
    const value = e.value;
    if (idx === 0) {
      this.startIP = value;
    } else {
      this.endIP = value;
    }
    this.ipErrMsg = this.validateIP(value, idx);

    if (this.ipErrMsg) {
      this.validation = false;
    } else {
      this.validation = true;
    }
  }

  validateIP(value: string, idx): string {
    if (!this.isValidIPregex(value)) {
      return 'Not valid IP format.';
    }
    if (!ipRangeCheck(value, this.probeHost.probe.cidr)) {
      return 'Not valid IP range.';
    }
    const ipArray = [this.startIP, this.endIP];
    const sortedIpArray = this.sortIP([this.startIP, this.endIP]);
    if (ipArray[0] !== sortedIpArray[0]) {
      return 'Not valiad range';
    }

    return null;
  }

  isValidIPregex(ip: string): boolean {
    if (this.ipVer === 'ipv4') {
      return /^(?=\d+\.\d+\.\d+\.\d+$)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.?){4}$/.test(ip);
    }
    return false;
  }

  sortIP(ipAddressArray) {
    return ipAddressArray.sort(function (a, b) {
      a = a.split('.');
      b = b.split('.');
      for (let i = 0; i < a.length; i++) {
        // tslint:disable-next-line:radix
        if ((a[i] = parseInt(a[i])) < (b[i] = parseInt(b[i]))) {
          return -1;
        } else if (a[i] > b[i]) {
          return 1;
        }
      }
      return 0;
    });
  }

  onInputPort(portNum: string, idx: number) {
    if (idx === 0) {
      this.startPort = portNum;
    } else {
      this.endPort = portNum;
    }
    this.portErrMsg = this.validatePort(portNum);

    if (this.portErrMsg) {
      this.validation = false;
    } else {
      this.validation = true;
    }
  }

  validatePort(portNum): string {
    if (Number(this.startPort) > Number(this.endPort)) {
      return 'Not valid port range.';
    }
    if (Number(portNum) <= 0 || Number(portNum) > 65535) {
      return 'Not valid port range.';
    }
    return null;
  }

}
