import {PeopleModel, RelevantPeopleModel} from './people.model';
import {PeopleMapModel} from './people-map.model';
import {BrokerModel} from './broker.model';
import {PayInModel} from './pay-in.model';
import {RewardModel} from './reward.model';
import {AuthService} from '../service/auth.service';
import {LoanSingleService} from '../service/loan.single.service';
import {MilestoneModel} from './milestone.model';

export interface LoanModelCallBacks {
   getUserName(userId: string): string;
   getUserPhotoUrl(userId: string): string;
   getUserRole(userId: string): string;
}


export class LoanModel {
  public Id: string;
  public Amount?: number;
  public Status?: string;
  public Milestones?: MilestoneModel[];
  public Item?: string;
  public Rating?: number;
  public Settlement?: Date;
  public Description?: string;
  public Lender?: string;
  public LenderLoanNumber?: string;
  public Client?: PeopleModel[];
  public Broker?: BrokerModel[];
  public OtherRewarder?: PeopleModel[];
  public Reward?: RewardModel[];
  public RewardPeople?: PeopleModel[];
  public PayIn?: PayInModel[];
  public PeopleMap?: PeopleMapModel[];
  public auth?: AuthService;
  public lss?: LoanSingleService;

  public ApplicationReceived: Date;
  public Lodgement: Date;
  public ValuationOrdered: Date;
  public ValuationCompleted: Date;
  public ConditionalApproved: Date;
  public OutstandingReturned: Date;
  public FormalApproved: Date;
  public SettlementBooked: Date;
  public SettlementCompleted: Date;

  constructor(payload: Partial<LoanModel>) {
      this.Id = payload.Id || '';
      this.Amount = payload.Amount || 0;
      this.Status = payload.Status || '';
      this.Milestones = [];
      if (Array.isArray(payload.Milestones)) {
        payload.Milestones.forEach(v => {
          this.Milestones.push(new MilestoneModel(v));
        });
      }
      this.Item = payload.Item || '';
      this.Rating = payload.Rating || 0;
      this.Settlement = payload.Settlement ? new Date(payload.Settlement) : new Date('1900-01-01') ;
      if ( this.Settlement.getFullYear() <= 1900 ){ this.Settlement = null ; }
      this.Description = payload.Description || '';
      this.Lender = payload.Lender || '';
      this.LenderLoanNumber = payload.LenderLoanNumber || '';

      if ( payload.Client  && payload.Client.length > 0 ){
        this.setClient(payload.Client);
      } else{
        this.Client = [];
      }

      if (payload.Broker && payload.Broker.length > 0 ) {
        this.setBroker(payload.Broker);
      }else{
        this.Broker = [];
      }

      if (payload.OtherRewarder && payload.OtherRewarder.length > 0 ) {
        this.setOtherRewarder(payload.OtherRewarder);
      }else{
        this.OtherRewarder = [];
      }

      if (payload.Reward && payload.Reward.length > 0 ) {
        this.setReward(payload.Reward);
      }else{
        this.Reward = [];
      }

      if (payload.RewardPeople && payload.RewardPeople.length > 0 ) {
        this.setRewardPeople(payload.RewardPeople);
      }else{
        this.RewardPeople = [];
      }

      if (payload.PayIn && payload.PayIn.length > 0 ) {
        this.setPayIn(payload.PayIn);
      }else{
        this.PayIn = [];
      }

      if (payload.PeopleMap && payload.PeopleMap.length > 0) {
        this.PeopleMap = payload.PeopleMap;
      }else{
        this.PeopleMap = [];
      }

      this.auth = payload.auth || null;
      this.lss = payload.lss || null;


      this.ApplicationReceived = this.getDate(payload.ApplicationReceived);
      this.Lodgement = this.getDate(payload.Lodgement);
      this.ValuationOrdered = this.getDate(payload.ValuationOrdered);
      this.ValuationCompleted = this.getDate(payload.ValuationCompleted);
      this.ConditionalApproved= this.getDate(payload.ConditionalApproved);
      this.OutstandingReturned= this.getDate(payload.OutstandingReturned);
      this.FormalApproved= this.getDate(payload.FormalApproved);
      this.SettlementBooked= this.getDate(payload.SettlementBooked);
      this.SettlementCompleted= this.getDate(payload.SettlementCompleted);
  }

  public static EmptyNew(lss: LoanSingleService, auth: AuthService): LoanModel {
    const nLoan = new LoanModel({
      Id: '',
      Amount: 0,
      Status: '',
      Item: '',
      Rating: 0,
      Settlement: new Date(),
      Description: '',
      Lender: '',
      LenderLoanNumber: '',
      Client: [],
      Broker: [],
      OtherRewarder: [],
      Reward: [],
      RewardPeople: [],
      PayIn: [],
      PeopleMap: [],
      auth, lss
    });
    return nLoan;
  }


  public set Response(resp: LoanModel) {
    this.Id = resp.Id;

    this.Amount = resp.Amount;
    this.Item = resp.Item;
    this.Rating = resp.Rating;
    this.Status = resp.Status;
    this.Settlement = new Date(resp.Settlement);
    if ( this.Settlement.getFullYear() <= 1900 ){ this.Settlement = null ; }
    this.Description = resp.Description;

    this.Lender = resp.Lender;
    this.LenderLoanNumber = resp.LenderLoanNumber;

    this.setClient(resp.Client);
    this.setBroker(resp.Broker);
    this.setOtherRewarder(resp.OtherRewarder);

    this.setReward(resp.Reward);
    this.setRewardPeople(resp.RewardPeople);
    this.PeopleMap = resp.PeopleMap;
    this.setPayIn(resp.PayIn);
  }

  private setReward(v: any[]): void{
    this.Reward = [];
    v.forEach((reward) => {
       this.addReward(
          reward.Amount,
          reward.Description,
          reward.Id,
          reward.LoanId,
          reward.PayOutId,
          reward.ToId,
          reward.FromId,
          reward.Ts);
    });
    return;
  }

  private setPayIn(v: any[]): void{
    this.PayIn = [];
    v.forEach( pi =>{
      this.PayIn.push(new PayInModel(pi));
    });
  }

  // Create or Update PayIn
  public cuPayIn(pi: PayInModel): void{
    // remove existing one
    const na = this.PayIn.filter(v => v.Id !== pi.Id );
    // add the incoming one
    na.unshift(
      new PayInModel(pi)
    );
    // update array element
    this.PayIn = na;
  }

  private setClient(v: any[]): void{
    this.Client = [];
    v.forEach((c) => {
      this.Client.push(
        new PeopleModel(c)
      );
    });
  }

  private setOtherRewarder(v: any[]): void{
      this.OtherRewarder = [];
      v.forEach((c) => {
        this.OtherRewarder.push(
          new PeopleModel(c)
        );
      });
  }

  private setBroker(v: any[]): void{
    this.Broker = [];
    v.forEach((b => {
      this.Broker.push(new BrokerModel(b) );
    }));
  }

  private setRewardPeople(v: any[]): void {
    this.RewardPeople = [];
    v.forEach((c) => {
      this.RewardPeople.push(
        new PeopleModel(c)
      );
    });
  }
  public addReward(Amount: number, Description: string, Id: number,
                   LoanId: string, PayOutId: number, ToId: string , FromId: string, Ts: Date): RewardModel {
    const r = new RewardModel(
      Amount,
      Description,
      Id,
      LoanId,
      PayOutId,
      ToId,
      FromId,
      new Date(Ts),
      this.callBacks()
    );
    r.LoanId = this.Id; // Make sure Loan Id is same
    this.Reward.unshift(r);
    return r;
  }

  public updateReward(Amount: number, Description: string, Id: number,
                      LoanId: string, PayOutId: number, ToId: string , FromId: string, Ts: Date): RewardModel {
    const r = new RewardModel(
      Amount,
      Description,
      Id,
      LoanId,
      PayOutId,
      ToId,
      FromId,
      new Date(Ts),
      this.callBacks()
    );
    r.LoanId = this.Id; // Make sure Loan Id is same
    const idx = this.Reward.findIndex( v => v.Id === Id );
    this.Reward[idx].Amount = Amount;
    this.Reward[idx].Description = Description;
    this.Reward[idx].LoanId = r.LoanId; // Ensure Loan Id is correct
    this.Reward[idx].PayOutId = PayOutId;
    this.Reward[idx].ToId = ToId;
    this.Reward[idx].FromId = FromId;
    this.Reward[idx].Ts = new Date(Ts);

    return r;
  }

  public removeReward(Id: number): void {
    const na = this.Reward.filter(v => v.Id !== Id );
    this.Reward = na;
  }

  // public emptyReward(): RewardModel {
  //   return new RewardModel(
  //     0,   '',      0, this.Id,
  //     0,       '',      '', new Date(), this.callBacks()
  //   );
  // }

  private callBacks(): LoanModelCallBacks {
    return {
      getUserName: this.getUserName.bind(this),
      getUserPhotoUrl: this.getUserPhotoUrl.bind(this),
      getUserRole: this.getUserRole.bind(this)
    };
  }

  public getUserName(id: string): string {
    let result = 'P:' + id;
    // search client
    this.Client.forEach(( c  => {
      if ( c.Id === id ) {
        result = c.First + ' ' + c.Last;
      }
    }));

    this.Broker.forEach(( c  => {
      if ( c.Id === id ) {
        result = c.First + ' ' + c.Last;
      }
    }));

    this.OtherRewarder.forEach(( c  => {
      if ( c.Id === id ) {
        result = c.First + ' ' + c.Last;
      }
    }));

    this.RewardPeople.forEach( c => {
       if (c.Id === id) {
         result = c.First + ' ' + c.Last;
       }
    });

    return result;
  }

  public getUserPhotoUrl(id: string): string {
    const url = this.auth.getUrl('avatar/') + id;
    return 'url("' + url + '")';
  }

  public getUserRole(id: string): string {
    let result = '';
    this.PeopleMap.forEach((row) => {
      if ( row.PeopleId === id ){
        result = row.Role;
      }
    });
    return result;
  }

  public getRelevantPeople(): RelevantPeopleModel[] {
    const result: RelevantPeopleModel[] = [];

    this.Client.forEach(( c  => {
      if ( !result.find( existing => existing.Id === c.Id ) ){
        result.push({Id: c.Id, Display: c.Display, Role: 'Client'} ) ;
      }

    }));

    this.Broker.forEach(( c  => {
      if ( !result.find( existing => existing.Id === c.Id ) ) {
        result.push({Id: c.Id, Display: c.Display, Role: 'Broker'});
      }
    }));

    this.OtherRewarder.forEach(( c  => {
      if ( !result.find( existing => existing.Id === c.Id ) ) {
        result.push({Id: c.Id, Display: c.Display, Role: this.getRoleById(c.Id)});
      }
    }));

    this.RewardPeople.forEach( c => {
      if ( !result.find( existing => existing.Id === c.Id ) ) {
        result.push({Id: c.Id, Display: c.Display, Role: 'none'});
      }
    });

    return result ; // [...new Set(result)]; // remove duplicates, if any
  }


  public getRoleById(id: string): string {
    let role = '';
    this.PeopleMap.every(v => {
      if (v.PeopleId === id) {
        role = v.Role;
        return false; // stop search
      }else{
        return true;
      }
    });
    return role;
  }

  // remove auth serivce and lss service for Json.stringify
  public cloneForJson(): LoanModel {
    return new LoanModel({
      Id: this.Id,
      Amount: this.Amount,
      Status: this.Status,
      Item: this.Item,
      Rating: this.Rating,
      Settlement: this.Settlement,
      Description: this.Description,
      Lender: this.Lender,
      LenderLoanNumber: this.LenderLoanNumber,
      Client: this.Client,
      Broker: this.Broker,
      OtherRewarder: this.OtherRewarder,
      Reward: this.Reward,
      RewardPeople: this.RewardPeople,
      PayIn: this.PayIn,
      PeopleMap: this.PeopleMap,
      auth: undefined,
      lss: undefined,

      ApplicationReceived: this.ApplicationReceived,
      Lodgement: this.Lodgement,
      ValuationOrdered: this.ValuationOrdered,
      ValuationCompleted: this.ValuationCompleted,
      ConditionalApproved: this.ConditionalApproved,
      OutstandingReturned: this.OutstandingReturned,
      FormalApproved: this.FormalApproved,
      SettlementBooked: this.SettlementBooked,
      SettlementCompleted: this.SettlementCompleted
    });
  }

  private getDate(field : any ): Date {
    let ret  = field ? new Date(field) : null ;
    if ( ret && ret !== null && ret.getFullYear() < 1900 ) return null ;
    return ret;
  }
}
