import { APIClient } from "./ApiClient";
import { Couple } from "./genealogy/CoupleApi";
import { Member } from "./genealogy/MemberApi";

interface FamilyAPI {
  user_id: number;
  family_id: number;
  name: string;
  time_create: number;
  is_admin: boolean;
  invitation_code: string;
  count_members: number;
  count_admins: number;
}

export class Family implements FamilyAPI {
  user_id: number;
  family_id: number;
  name: string;
  time_create: number;
  is_admin: boolean;
  invitation_code: string;
  count_members: number;
  count_admins: number;

  constructor(f: FamilyAPI) {
    this.user_id = f.user_id;
    this.family_id = f.family_id;
    this.name = f.name;
    this.time_create = f.time_create;
    this.is_admin = f.is_admin;
    this.invitation_code = f.invitation_code;
    this.count_members = f.count_members;
    this.count_admins = f.count_admins;
  }

  /**
   * Check if the current user user can leave a family
   */
  get CanLeave(): boolean {
    return !this.is_admin || this.count_admins > 1;
  }

  /**
   * Get application URL for family
   */
  URL(uri?: string): string {
    return `/family/${this.family_id}/${uri ?? ""}`;
  }

  /**
   * Get base family URL
   */
  get BaseURL(): string {
    return this.URL("");
  }

  /**
   * Get application URL for member page
   */
  memberURL(member: Member, edit?: boolean): string {
    return (
      `/family/${this.family_id}/genealogy/member/${member.id}` +
      (edit ? "/edit" : "")
    );
  }

  /**
   * Get family tree URL for member
   */
  familyTreeURL(member: Member | number): string {
    return `/family/${this.family_id}/genealogy/tree/${
      typeof member === "number" ? member : member.id
    }`;
  }

  /**
   * Get application URL for couple page
   */
  coupleURL(member: Couple, edit?: boolean): string {
    return (
      `/family/${this.family_id}/genealogy/couple/${member.id}` +
      (edit ? "/edit" : "")
    );
  }
}

export class ExtendedFamilyInfo extends Family {
  public disable_couple_photos: boolean;
  public enable_genealogy: boolean;
  public enable_accommodations: boolean;
  constructor(p: any) {
    super(p);
    this.disable_couple_photos = p.disable_couple_photos;
    this.enable_genealogy = p.enable_genealogy;
    this.enable_accommodations = p.enable_accommodations;
  }
}

export enum JoinFamilyResult {
  TooManyRequests,
  InvalidCode,
  AlreadyMember,
  Error,
  Success,
}

export interface FamilyUser {
  user_id: number;
  family_id: number;
  time_create: number;
  is_admin: boolean;
  user_name: string;
  user_mail: string;
}

export class FamilyApi {
  /**
   * Create a new family
   */
  static async CreateFamily(name: string): Promise<void> {
    await APIClient.exec({
      method: "POST",
      uri: "/family/create",
      jsonData: { name: name },
    });
  }

  /**
   * Join an existing family
   */
  static async JoinFamily(code: string): Promise<JoinFamilyResult> {
    const res = await APIClient.exec({
      method: "POST",
      uri: "/family/join",
      allowFail: true,
      jsonData: { code: code },
    });

    if (res.status >= 200 && res.status < 300) return JoinFamilyResult.Success;

    switch (res.status) {
      case 429:
        return JoinFamilyResult.TooManyRequests;
      case 404:
        return JoinFamilyResult.InvalidCode;
      case 409:
        return JoinFamilyResult.AlreadyMember;
      default:
        return JoinFamilyResult.Error;
    }
  }

  /**
   * Get the list of families
   */
  static async GetList(): Promise<Family[]> {
    return (
      await APIClient.exec({
        method: "GET",
        uri: "/family/list",
      })
    ).data.map((f: FamilyAPI) => new Family(f));
  }

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

    return new ExtendedFamilyInfo(res.data);
  }

  /**
   * Attempt to leave a family
   */
  static async LeaveFamily(id: number): Promise<void> {
    await APIClient.exec({
      method: "POST",
      uri: `/family/${id}/leave`,
    });
  }

  /**
   * Renew a family invitation code
   */
  static async RenewInvitationCode(id: number): Promise<void> {
    await APIClient.exec({
      method: "POST",
      uri: `/family/${id}/renew_invitation_code`,
    });
  }

  /**
   * Get the users of a family
   */
  static async GetUsersList(id: number): Promise<FamilyUser[]> {
    return (
      await APIClient.exec({
        method: "GET",
        uri: `/family/${id}/users`,
      })
    ).data;
  }

  /**
   * Update a user of the family
   */
  static async UpdateUser(user: FamilyUser): Promise<void> {
    await APIClient.exec({
      method: "PATCH",
      uri: `/family/${user.family_id}/user/${user.user_id}`,
      jsonData: {
        is_admin: user.is_admin,
      },
    });
  }

  /**
   * Remove a member from the family
   */
  static async RemoveUser(user: FamilyUser): Promise<void> {
    await APIClient.exec({
      method: "DELETE",
      uri: `/family/${user.family_id}/user/${user.user_id}`,
    });
  }

  /**
   * Update a family settings
   */
  static async UpdateFamily(settings: {
    id: number;
    name?: string;
    enable_genealogy?: boolean;
    enable_accommodations?: boolean;
    disable_couple_photos?: boolean;
  }): Promise<void> {
    await APIClient.exec({
      method: "PATCH",
      uri: `/family/${settings.id}`,
      jsonData: {
        name: settings.name,
        enable_genealogy: settings.enable_genealogy,
        enable_accommodations: settings.enable_accommodations,
        disable_couple_photos: settings.disable_couple_photos,
      },
    });
  }

  /**
   * Delete a family
   */
  static async DeleteFamily(family: Family) {
    await APIClient.exec({
      method: "DELETE",
      uri: `/family/${family.family_id}`,
    });
  }
}
