import { APIClient } from "../ApiClient";
import { DateValue, Member } from "./MemberApi";
import { ServerApi } from "../ServerApi";

interface CoupleApiInterface {
  id: number;
  family_id: number;
  wife?: number;
  husband?: number;
  state?: string;
  photo_id?: string;
  signed_photo_id?: string;
  time_create?: number;
  time_update?: number;
  wedding_year?: number;
  wedding_month?: number;
  wedding_day?: number;
  divorce_year?: number;
  divorce_month?: number;
  divorce_day?: number;
}

export class Couple implements CoupleApiInterface {
  id: number;
  family_id: number;
  wife?: number;
  husband?: number;
  state?: string;
  photo_id?: string;
  signed_photo_id?: string;
  time_create?: number;
  time_update?: number;
  wedding_year?: number;
  wedding_month?: number;
  wedding_day?: number;
  divorce_year?: number;
  divorce_month?: number;
  divorce_day?: number;

  constructor(int: CoupleApiInterface) {
    this.id = int.id;
    this.family_id = int.family_id;
    this.wife = int.wife;
    this.husband = int.husband;
    this.state = int.state;
    this.photo_id = int.photo_id;
    this.signed_photo_id = int.signed_photo_id;
    this.time_create = int.time_create;
    this.time_update = int.time_update;
    this.wedding_year = int.wedding_year;
    this.wedding_month = int.wedding_month;
    this.wedding_day = int.wedding_day;
    this.divorce_year = int.divorce_year;
    this.divorce_month = int.divorce_month;
    this.divorce_day = int.divorce_day;
  }

  /**
   * Create an empty couple object
   */
  static New(family_id: number): Couple {
    return new Couple({
      id: 0,
      family_id: family_id,
    });
  }

  get hasPhoto(): boolean {
    return this.photo_id !== null;
  }

  get photoURL(): string | null {
    if (!this.signed_photo_id) return null;
    return `${APIClient.backendURL()}/photo/${this.signed_photo_id}`;
  }

  get thumbnailURL(): string | null {
    if (!this.signed_photo_id) return null;
    return `${APIClient.backendURL()}/photo/${this.signed_photo_id}/thumbnail`;
  }

  get dateOfWedding(): DateValue | undefined {
    if (!this.wedding_day && !this.wedding_month && !this.wedding_year)
      return undefined;

    return {
      year: this.wedding_year,
      month: this.wedding_month,
      day: this.wedding_day,
    };
  }

  get dateOfDivorce(): DateValue | undefined {
    if (!this.divorce_day && !this.divorce_month && !this.divorce_year)
      return undefined;

    return {
      year: this.divorce_year,
      month: this.divorce_month,
      day: this.divorce_day,
    };
  }

  otherPersonID(id: number): number | undefined {
    return id === this.wife ? this.husband : this.wife;
  }

  get stateFr(): string {
    return (
      ServerApi.Config.couples_states.find((c) => c.code === this.state)?.fr ??
      ""
    );
  }
}

export class CouplesList {
  private list: Couple[];
  private map: Map<number, Couple>;

  constructor(list: Couple[]) {
    this.list = list;
    this.map = new Map();

    for (const m of list) {
      this.map.set(m.id, m);
    }
  }

  public get isEmpty(): boolean {
    return this.list.length === 0;
  }

  public get size(): number {
    return this.list.length;
  }

  public get fullList(): Couple[] {
    return this.list;
  }

  filter(predicate: (m: Couple) => boolean): Couple[] {
    return this.list.filter(predicate);
  }

  get(id: number): Couple | undefined {
    return this.map.get(id);
  }

  getAllOf(m: Member): Couple[] {
    return this.filter((c) => c.husband === m.id || c.wife === m.id);
  }

  getFirstMariedOf(m: Member): Couple | undefined {
    return this.getAllOf(m).find((c) => (c.state = "M"));
  }
}

export class CoupleApi {
  /**
   * Create a new couple
   */
  static async Create(m: Couple): Promise<Couple> {
    const res = await APIClient.exec({
      uri: `/family/${m.family_id}/genealogy/couple/create`,
      method: "POST",
      jsonData: m,
    });

    return new Couple(res.data);
  }

  /**
   * Get the information about a single couple
   */
  static async GetSingle(
    family_id: number,
    couple_id: number
  ): Promise<Couple> {
    const res = await APIClient.exec({
      uri: `/family/${family_id}/genealogy/couple/${couple_id}`,
      method: "GET",
    });

    return new Couple(res.data);
  }

  /**
   * Get the entire list of couples of a family
   */
  static async GetEntireList(family_id: number): Promise<CouplesList> {
    const res = await APIClient.exec({
      uri: `/family/${family_id}/genealogy/couples`,
      method: "GET",
    });

    return new CouplesList(res.data.map((d: any) => new Couple(d)));
  }

  /**
   * Update a couple information
   */
  static async Update(m: Couple): Promise<void> {
    await APIClient.exec({
      uri: `/family/${m.family_id}/genealogy/couple/${m.id}`,
      method: "PUT",
      jsonData: m,
    });
  }

  /**
   * Set a new photo for a couple
   */
  static async SetCouplePhoto(m: Couple, b: Blob): Promise<void> {
    const fd = new FormData();
    fd.append("photo", b);
    await APIClient.exec({
      uri: `/family/${m.family_id}/genealogy/couple/${m.id}/photo`,
      method: "PUT",
      formData: fd,
    });
  }

  /**
   * Remove the photo of a couple
   */
  static async RemoveCouplePhoto(m: Couple): Promise<void> {
    await APIClient.exec({
      uri: `/family/${m.family_id}/genealogy/couple/${m.id}/photo`,
      method: "DELETE",
    });
  }

  /**
   * Delete a family couple
   */
  static async Delete(m: Couple): Promise<void> {
    await APIClient.exec({
      uri: `/family/${m.family_id}/genealogy/couple/${m.id}`,
      method: "DELETE",
    });
  }
}
