import { SoftTargetTypeEditComponent } from './../soft-target-type-edit/soft-target-type-edit.component';
import { SoftTargetType } from 'src/app/core/model/soft-target-type';
import { SelectData } from './../../core/model/select-data.model';
import { DialogService } from './../../core/dialog.service';
import { MatDialog } from '@angular/material/dialog';
import { AttackerEditComponent } from './../attacker-edit/attacker-edit.component';
import { Attacker } from './../model/attacker.model';
import { AttacksFeatureState, AttacksState } from './../store/attacks.redurecs';
import { AttackFormData } from './../model/attack-form-data';
import { Subscription, Observable } from 'rxjs';
import { FormGroup, FormControl, Validators, FormArray } from '@angular/forms';
import { AttacksService } from './../attacks.service';
import { Component, OnInit, OnDestroy, Renderer2 } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { map, tap } from 'rxjs/operators';
import * as moment from 'moment';
import { Store } from '@ngrx/store';
import { Attack } from '../model/attack.model';
import { RequestAttacksListAction, RemoveAttackAction } from '../store/attacks.actions';
import { RelatedAttack } from '../model/related-attack.model';
import { RelatedAttackEditComponent } from '../related-attack-edit/related-attack-edit.component';

@Component({
  selector: 'app-attack-edit',
  templateUrl: './attack-edit.component.html',
  styleUrls: ['./attack-edit.component.scss']
})
export class AttackEditComponent implements OnInit, OnDestroy {

  private attackForm: FormGroup = this.initAttackForm();

  private countries: Observable<String[]>;
  private cities: Observable<String[]>;
  private softTargetDescriptions: Observable<String[]>;
  private terroristOrganizations: Observable<String[]>;

  public editMode = false;

  private formDataSubscription: Subscription;
  public formData: AttackFormData;

  public attacks: Attack[];

  private storeSubscription: Subscription;

  constructor(private attacksService: AttacksService, private store: Store<AttacksFeatureState>, private route: ActivatedRoute, private router: Router, private dialog: MatDialog, private renderer: Renderer2) {
    let id = this.route.snapshot.params['id'];
    if(id)
      this.editMode = true; 
    this.storeSubscription = this.store.select('attacks').subscribe(
      (state: AttacksState) => {
        if (state.attacks === null)
          store.dispatch(new RequestAttacksListAction());
        else {
          this.attacks = state.attacks;
          if (this.editMode){
            let attack: Attack = state.attacks.find((attack: Attack) => attack.id === +id);
            if (!attack)
              router.navigate(['/database'])
            else {
              this.attackForm = this.initAttackForm(attack);
            }
          }
        }
      }
    );
    this.formDataSubscription = this.attacksService.attackFormData.subscribe(
      (formData: AttackFormData) => {
        this.formData = formData;
        setTimeout(() => {
          this.countries = this.attackForm.get('country').valueChanges.pipe(
            map(inputValue => this.filterAutoComplete(inputValue, this.formData.countries))
          );
          this.cities = this.attackForm.get('city').valueChanges.pipe(
            map(inputValue => this.filterAutoComplete(inputValue, this.formData.cities))
          );
          this.terroristOrganizations = this.attackForm.get('terroristOrganization').valueChanges.pipe(
            map(inputValue => this.filterAutoComplete(inputValue, this.formData.terroristOrganizations))
          );
          this.softTargetDescriptions = this.attackForm.get('softTargetDescription').valueChanges.pipe(
            map(inputValue => this.filterAutoComplete(inputValue, this.formData.softTargetDescriptions))
          );
        }, 0);
      }
    );
  }

  ngOnInit() {
  }

  onAttackFormSubmit(){
    if (this.editMode)
      this.attacksService.updateAttackRecord(this.attackForm, "/database");
    else
      this.attacksService.createAttackRecord(this.attackForm, "/database");
  }

  onAddAttacker(){
    let attackerDialog = this.dialog.open(AttackerEditComponent, {
      data: { attacker: null, genders: this.formData.genders, localities: this.formData.localities },
    });
    attackerDialog.afterClosed().subscribe((attacker: FormGroup) => {
      if (attacker){
        let attackers = <FormArray>this.attackForm.get('attackers');
        attackers.push(attacker);
      }
    });
  }

  onAddRelatedAttack(){
    let relatedAttackDialog = this.dialog.open(RelatedAttackEditComponent, {
      data: { forbiddenIds: this.editMode ? this.getForbiddenIds() : null }
    });
    relatedAttackDialog.afterClosed().subscribe((relatedAttack: FormGroup) => {
      if (relatedAttack){
        let relatedAttackId =  relatedAttack.value.relatedAttackId.id;
        relatedAttack.value.relatedAttackId = relatedAttackId;

        if (this.editMode){
          let currentUserId: number = this.attackForm.get('id').value;
          let relatedAttackWithSameId: RelatedAttack = this.attackForm.get('relatedAttacks').value.find((attack: RelatedAttack) => { return attack.relatedAttackId === relatedAttackId });
          if (relatedAttackId === currentUserId || relatedAttackWithSameId){
            console.warn("related attack wasn't added, because it's already related, or it's current attack");
            return;
          }
        }

        let relatedAttacks = <FormArray>this.attackForm.get('relatedAttacks');
        relatedAttacks.push(relatedAttack);
      }
    });
  }
  
  onAddSoftTargetType(){
    let currentTargetTypes: string[] = this.attackForm.get('softTargetTypes').value.map(item => item.softTargetType);
    let softTargetTypeDialog = this.dialog.open(SoftTargetTypeEditComponent, {
      data: { softTargetTypes: this.formData.softTargetTypes.filter((softTargetType: SelectData) => !currentTargetTypes.includes(<string>softTargetType.name)) },
      width: '500px',
    });
    softTargetTypeDialog.afterClosed().subscribe((softTargetType: FormGroup) => {
      if (softTargetType){
        let softTargetTypes = <FormArray>this.attackForm.get('softTargetTypes');
        softTargetTypes.push(softTargetType);
      }
    });
  }

  onEditAttacker(attacker: Attacker){
    let attackerDialog = this.dialog.open(AttackerEditComponent, {
      data: { attacker: attacker, genders: this.formData.genders, localities: this.formData.localities },
    });
    attackerDialog.afterClosed().subscribe((attacker: FormGroup) => {
      if (attacker){
        let attackers = <FormArray>this.attackForm.get('attackers');
        let attackerId = attacker.get('id').value;
        let attackerIndex = attackers.value.findIndex((attacker: Attacker) => attacker.id === attackerId);
        if (attackerIndex > -1){
          attackers.at(attackerIndex).patchValue(attacker.value);
        }
      }
    });
  }

  onDeleteAttacker($event: any, attackerToDelete: Attacker){
    let matListItem = $event.target.closest('mat-list-item');
    let attackers: FormArray = <FormArray>this.attackForm.get('attackers');
    let index: number = attackers.value.findIndex((attacker: Attacker) => { return attacker === attackerToDelete });
    if (index > -1 && matListItem !== null){
      this.renderer.addClass(matListItem, "hidden");
      setTimeout(() => attackers.removeAt(index), 200);
    }
  }

  onUnlinkRelatedAttack($event: any, relatedAttackId: number){
    let matListItem = $event.target.closest('mat-list-item');
    let relatedAttacks: FormArray = <FormArray>this.attackForm.get('relatedAttacks');
    let index: number = relatedAttacks.value.findIndex((relatedAttack: RelatedAttack) => relatedAttack.relatedAttackId === relatedAttackId);
    if (index > -1 && matListItem !== null){
      this.renderer.addClass(matListItem, "hidden");
      setTimeout(() => relatedAttacks.removeAt(index), 200);
    }
  }

  onUnlinkSoftTargetType($event: any, softTargetTypeName: string){
    let matListItem = $event.target.closest('mat-list-item');
    let softTargetTypes: FormArray = <FormArray>this.attackForm.get('softTargetTypes');
    let index: number = softTargetTypes.value.findIndex((softTargetType) => softTargetType.softTargetType === softTargetTypeName);
    if (index > -1 && matListItem !== null){
      this.renderer.addClass(matListItem, "hidden");
      setTimeout(() => softTargetTypes.removeAt(index), 200);
    }
  }

  onDeleteAttack(){
    this.attacksService.deleteAttackRecord(this.attackForm.get('id').value, "/database");
  }

  ngOnDestroy(){
    if(this.storeSubscription)
      this.storeSubscription.unsubscribe();
    this.formDataSubscription.unsubscribe();
  }

  private getForbiddenIds(){
    if (this.editMode){
      let forbiddenIds: number[] = [this.attackForm.get('id').value];
      forbiddenIds = forbiddenIds.concat(this.attackForm.get('relatedAttacks').value.map((relatedAttack: RelatedAttack) => { return relatedAttack.relatedAttackId }));
      return forbiddenIds;
    }
    return null;
  }

  private getRelatedAttackDescById(id: number): string{
    let attack: Attack = this.attacks.find((attack: Attack) => { return attack.id === id });
    return attack ? attack.city+", "+attack.country+", "+attack.date : '';
  }

  private getSoftTargetTypeLabelByName(name: string): string{
    let type: SelectData = this.formData.softTargetTypes.find((softTargetType: SelectData) => softTargetType.name === name);
    return type ? <string>type.label : name;
  }

  private filterAutoComplete(input: String, values: String[]){
    let inputValue = input.toLocaleLowerCase();
    return values.filter(value => value.toLocaleLowerCase().includes(inputValue));
  }

  private initAttackForm(attack?: Attack): FormGroup{
    let attackers: FormArray = new FormArray([]);
    let relatedAttacks: FormArray = new FormArray([]);
    let softTargetTypes: FormArray = new FormArray([]);
    if (attack){
      for(let attacker of attack.attackers){
        attackers.push(new FormGroup({
          'id': new FormControl(attacker.id),
          'name': new FormControl(attacker.name),
          'gender': new FormControl(attacker && attacker.gender ? attacker.gender.name : null),
          'age': new FormControl(attacker.age),
          'attackLocality': new FormControl(attacker && attacker.attackLocality ? attacker.attackLocality.name : null),
          'residence' : new FormControl(attacker.residence),
          'origin': new FormControl(attacker.origin)
        }));
      }
      for (let relatedAttack of attack.relatedAttacks){
        relatedAttacks.push(new FormGroup({
          'id': new FormControl(relatedAttack.id),
          'relatedAttackId': new FormControl(relatedAttack.relatedAttackId),
          'note': new FormControl(relatedAttack.note)
        }));
      }
      for(let softTargetType of attack.softTargetTypes){
        softTargetTypes.push(new FormGroup({
          'id': new FormControl(softTargetType.id),
          'softTargetType': new FormControl(softTargetType.softTargetType.name),
          'softTargetTypeDetail': new FormControl(softTargetType.softTargetTypeDetail)
        }));
      }
    }
    let formControls = {
      'id': new FormControl(attack ? attack.id : null),
      'country': new FormControl(attack ? attack.country : null, [Validators.required, Validators.maxLength(50)]),
      'city': new FormControl(attack ? attack.city : null, [Validators.required, Validators.maxLength(50)]),
      'time': new FormControl(attack ? attack.time : moment().locale('cs').subtract(1, 'hours').format('LT')),
      'date': new FormControl(attack ? moment(<string>attack.date, 'D.M.YYYY').locale('cs') : moment().locale('cs'), Validators.required),
      'peak': new FormControl(attack ? attack.peak : moment().locale('cs').subtract(30, 'minutes').format('LT')),
      'latitude': new FormControl(attack ? attack.latitude : null, [Validators.min(-90), Validators.max(90), Validators.pattern("^-?[0-9]+(\.[0-9]{1,6})?$")]),
      'longitude': new FormControl(attack ? attack.longitude : null, [Validators.min(-180), Validators.max(180), Validators.pattern("^-?[0-9]+(\.[0-9]{1,6})?$")]),
      'softTargetTypes': softTargetTypes,
      'softTargetDescription': new FormControl(attack ? attack.softTargetDescription : null, Validators.maxLength(200)),
      'terror': new FormControl(attack && attack.terror ? attack.terror.name : null),
      'epicenter': new FormControl(attack && attack.epicenter ? attack.epicenter.name : null),
      'modusOperandi': new FormControl(attack && attack.modusOperandi ? attack.modusOperandi.name : null),
      'modusOperandiDetail': new FormControl(attack ? attack.modusOperandiDetail : null, Validators.maxLength(200)),
      'entranceSecurity': new FormControl(attack && attack.entranceSecurity ? attack.entranceSecurity.name : null),
      'terroristOrganization': new FormControl(attack ? attack.terroristOrganization : null, Validators.maxLength(200)),
      'attackers': attackers,
      'deaths': new FormControl(attack ? attack.deaths : null),
      'injured': new FormControl(attack ? attack.injured : null),
      'potentialVictims': new FormControl(attack ? attack.potentialVictims : null),
      'relatedAttacks': relatedAttacks,
      'note': new FormControl(attack ? attack.note : null, Validators.maxLength(1000)),
      'link': new FormControl(attack ? attack.link : null, Validators.maxLength(1000))
    }
    if (this.editMode){
    }
    return new FormGroup(formControls);
  }

}
