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';

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


export class LoanModel {
  constructor(
    public Id: string,
    public Amount?: number,
    public Status?: string,
    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 static EmptyNew(lss: LoanSingleService, auth: AuthService): LoanModel {
    const nLoan = new LoanModel(
      '', 0 , '', '', 0, new Date(), '',
      '', '', [], [], [], [], [], [], [],
      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);
    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.To,
          reward.From,
          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.Id, c.First, c.Last, c.Middle, c.Title, c.Display, c.Nick, c.Enabled)
      );
    });
  }

  private setOtherRewarder(v: any[]): void{
      this.OtherRewarder = [];
      v.forEach((c) => {
        this.OtherRewarder.push(
          new PeopleModel(c.Id, c.First, c.Last, c.Middle, c.Title, c.Display, c.Nick, c.Enabled)
        );
      });
  }

  private setBroker(v: any[]): void{
    this.Broker = [];
    v.forEach((b => {
      this.Broker.push(new BrokerModel(
            b.Id, b.First, b.Last, b.Middle, b.Title, b.Display, b.Nick, b.Login, b.Enabled, b.BSB, b.ACC, b.License, b.Organization
        )
      );
    }));
  }

  private setRewardPeople(v: any[]): void {
    this.RewardPeople = [];
    v.forEach((c) => {
      this.RewardPeople.push(
        new PeopleModel(c.Id, c.First, c.Last, c.Middle, c.Title, c.Display, c.Nick, c.Enabled)
      );
    });
  }
  public addReward(Amount: number, Description: string, Id: number,
                   LoanId: string, PayOutId: number, To: string , From: string, Ts: Date): RewardModel {
    const r = new RewardModel(
      Amount,
      Description,
      Id,
      LoanId,
      PayOutId,
      To,
      From,
      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, To: string , From: string, Ts: Date): RewardModel {
    const r = new RewardModel(
      Amount,
      Description,
      Id,
      LoanId,
      PayOutId,
      To,
      From,
      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].To = To;
    this.Reward[idx].From = From;
    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  => {
      result.push({Id: c.Id, Display: c.Display, Role: 'Client'} ) ;
    }));

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

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

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

    return [...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(
      this.Id,
      this.Amount,
      this.Status,
      this.Item,
      this.Rating,
      this.Settlement,
      this.Description,
      this.Lender,
      this.LenderLoanNumber,
      this.Client,
      this.Broker,
      this.OtherRewarder,
      this.Reward,
      this.RewardPeople,
      this.PayIn,
      this.PeopleMap,
      undefined,
      undefined
    );
  }
}
