import {
  Address,
  Center,
  Civility,
  DateTime,
  User,
  UserGroup,
  Household,
  WorkflowAvailable,
  Scope,
  Job,
  PrivateCommentEmbeddable,
  TranslatableString,
  DateTimeWrite,
  SetGender,
  SetCenter,
  SetCivility,
  Gender,
} from "ChillMainAssets/types";
import { StoredObject } from "ChillDocStoreAssets/types";
import { Thirdparty } from "../../../ChillThirdPartyBundle/Resources/public/types";
import { Calendar } from "../../../ChillCalendarBundle/Resources/public/types";

/**
 * An alternative name, as configured locally
 */
export interface AltName {
  labels: TranslatableString;
  key: string;
}

export interface PersonAltNameWrite {
  key: string;
  value: string;
}

/**
 * An altname for a person
 */
export interface PersonAltName {
  label: string;
  /**
   * will match a key in @link{AltName}
   */
  key: string;
}

export interface Person {
  id: number;
  type: "person";
  text: string;
  textAge: string;
  firstName: string;
  lastName: string;
  altNames: PersonAltName[];
  suffixText: string;
  current_household_address: Address | null;
  birthdate: DateTime | null;
  deathdate: DateTime | null;
  age: number;
  phonenumber: string;
  mobilenumber: string;
  email: string;
  gender: Gender;
  centers: Center[];
  civility: Civility | null;
  current_household_id: number;
  current_residential_addresses: ResidentialAddress[];
  /**
   * The person id as configured by the user
   */
  personId: string;
  identifiers: PersonIdentifier[];
}

export interface PersonIdentifier {
  id: number;
  type: "person_identifier";
  value: object;
  definition: PersonIdentifierDefinition;
}

export interface PersonIdentifierDefinition {
  id: number;
  type: "person_identifier_definition";
  engine: string;
}

export interface ResidentialAddress {
  address: Address | null;
  endDate: DateTime | null;
  hostPerson: Person | null;
  hostThirdParty: Thirdparty | null;
  startDate: DateTime | null;
}

export interface PersonIdentifierWrite {
  type: "person_identifier";
  definition_id: number;
  value: object;
}

/**
 * Person representation to create or update a Person
 */
export interface PersonWrite {
  type: "person";
  firstName: string;
  lastName: string;
  altNames: PersonAltNameWrite[];
  addressId: number | null;
  birthdate: DateTimeWrite | null;
  deathdate: DateTimeWrite | null;
  phonenumber: string;
  mobilenumber: string;
  email: string;
  gender: SetGender | null;
  center: SetCenter | null;
  civility: SetCivility | null;
  identifiers: PersonIdentifierWrite[];
}

export interface AccompanyingPeriod {
  id: number;
  type: "accompanying_period";
  addressLocation?: Address | null;
  administrativeLocation?: Location | null;
  calendars: Calendar[];
  closingDate?: Date | null;
  closingMotive?: ClosingMotive | null;
  comments: Comment[];
  confidential: boolean;
  createdAt?: Date | null;
  createdBy?: User | null;
  emergency: boolean;
  intensity?: "occasional" | "regular";
  job?: Job | null;
  locationHistories: AccompanyingPeriodLocationHistory[];
  openingDate?: Date | null;
  origin?: Origin | null;
  participations: AccompanyingPeriodParticipation[];
  personLocation?: Person | null;
  pinnedComment?: Comment | null;
  preventUserIsChangedNotification: boolean;
  remark: string;
  requestorAnonymous: boolean;
  requestorPerson?: Person | null;
  requestorThirdParty?: Thirdparty | null;
  resources: AccompanyingPeriodResource[];
  scopes: Scope[];
  socialIssues: SocialIssue[];
  step?:
    | "CLOSED"
    | "CONFIRMED"
    | "CONFIRMED_INACTIVE_SHORT"
    | "CONFIRMED_INACTIVE_LONG"
    | "DRAFT";
}

export interface AccompanyingPeriodWorkEvaluationDocument {
  id: number;
  type: "accompanying_period_work_evaluation_document";
  storedObject: StoredObject;
  title: string;
  createdAt: DateTime | null;
  createdBy: User | null;
  updatedAt: DateTime | null;
  updatedBy: User | null;
  workflows_availables: WorkflowAvailable[];
  workflows: object[];
}

export interface AccompanyingPeriodWork {
  id?: number;
  type: "accompanying_period_work";
  accompanyingPeriod?: AccompanyingPeriod;
  accompanyingPeriodWorkEvaluations: AccompanyingPeriodWorkEvaluation[];
  createdAt?: string;
  createdAutomatically: boolean;
  createdAutomaticallyReason: string;
  createdBy: User;
  endDate?: string;
  goals: AccompanyingPeriodWorkGoal[];
  handlingThierParty?: Thirdparty;
  note: string;
  persons: Person[];
  privateComment: PrivateCommentEmbeddable;
  referrersHistory: AccompanyingPeriodWorkReferrerHistory[];
  results: Result[];
  socialAction?: SocialAction;
  startDate?: string;
  thirdParties: Thirdparty[];
  updatedAt?: string;
  updatedBy: User;
  version: number;
}

interface SocialAction {
  id: number;
  parent?: SocialAction | null;
  children: SocialAction[];
  issue?: SocialIssue | null;
  ordering: number;
  title: {
    fr: string;
  };
  text: string;
  defaultNotificationDelay?: string | null;
  desactivationDate?: string | null;
  evaluations: Evaluation[];
  goals: Goal[];
  results: Result[];
}

export interface AccompanyingPeriodResource {
  id: number;
  accompanyingPeriod: AccompanyingPeriod;
  comment?: string | null;
  person?: Person | null;
  thirdParty?: Thirdparty | null;
}

export interface Origin {
  id: number;
  label: {
    fr: string;
  };
  noActiveAfter: DateTime;
}

export interface ClosingMotive {
  id: number;
  active: boolean;
  name: {
    fr: string;
  };
  ordering: number;
  isCanceledAccompanyingPeriod: boolean;
  parent?: ClosingMotive | null;
  children: ClosingMotive[];
}

export interface AccompanyingPeriodParticipation {
  id: number;
  startDate: DateTime;
  endDate?: DateTime | null;
  accompanyingPeriod: AccompanyingPeriod;
  person: Person;
}

export interface AccompanyingPeriodLocationHistory {
  id: number;
  startDate: DateTime;
  endDate?: DateTime | null;
  addressLocation?: Address | null;
  period: AccompanyingPeriod;
  personLocation?: Person | null;
}

export interface SocialIssue {
  id: number;
  text: string;
  parent?: SocialIssue | null;
  children: SocialIssue[];
  socialActions?: SocialAction[] | null;
  ordering: number;
  title: {
    fr: string;
  };
  desactivationDate?: string | null;
}

export interface Goal {
  id: number;
  results: Result[];
  socialActions?: SocialAction[] | null;
  title: {
    fr: string;
  };
}

export interface Result {
  id: number;
  accompanyingPeriodWorks: AccompanyingPeriodWork[];
  accompanyingPeriodWorkGoals: AccompanyingPeriodWorkGoal[];
  goals: Goal[];
  socialActions: SocialAction[];
  title: {
    fr: string;
  };
  desactivationDate?: string | null;
}

export interface AccompanyingPeriodWorkGoal {
  id: number;
  accompanyingPeriodWork: AccompanyingPeriodWork;
  goal: Goal;
  note: string;
  results: Result[];
}

export interface AccompanyingPeriodWorkEvaluation {
  type: "accompanying_period_work_evaluation";
  accompanyingPeriodWork: AccompanyingPeriodWork | null;
  comment: string;
  createdAt: DateTime | null;
  createdBy: User | null;
  documents: AccompanyingPeriodWorkEvaluationDocument[];
  endDate: DateTime | null;
  evaluation: Evaluation | null;
  id: number | null;
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  key: any;
  maxDate: DateTime | null;
  startDate: DateTime | null;
  updatedAt: DateTime | null;
  updatedBy: User | null;
  warningInterval: string | null;
  timeSpent: number | null;
}

export interface Evaluation {
  id: number;
  url: string;
  socialActions: SocialAction[];
  title: {
    fr: string;
  };
  active: boolean;
  delay: string;
  notificationDelay: string;
}

export interface Step {
  currentStep: {
    text: string;
  };
}

export interface Workflow {
  id: number;
  title: string;
  type: "accompanying_period_work" | "accompanying_period";
  isOnHoldAtCurrentStep: boolean;
  datas: {
    persons: Person[];
  };
  steps: Step[];
}

export interface WorflowCc {
  id: number;
  title: string;
  isOnHoldAtCurrentStep: boolean;
  datas: {
    persons: Person[];
  };
  steps: Step[];
}

export interface Warning {
  id: number;
  warningDate: DateTime;
  endDate: DateTime;
  title: string;
}
export interface Alert {
  id: number;
  warningDate: DateTime;
  endDate: DateTime;
  title: string;
}

export interface Notification {
  id: number;
  date: DateTime;
  title: string;
  sender: {
    text: string;
  };
  relatedEntityClass: string;
  relatedEntityId: number;
}

export interface Participation {
  person: Person;
}
export interface AccompanyingCourse {
  id: number;
  openingDate: DateTime;
  socialIssues: SocialIssue[];
  participations: Participation[];
  emergency: boolean;
  confidential: boolean;
}

export interface AccompanyingPeriodWorkReferrerHistory {
  id: number;
  accompanyingPeriodWork: AccompanyingPeriodWork;
  user: User;
  startDate: DateTime;
  endDate: DateTime | null;
  createdAt: DateTime;
  updatedAt: DateTime | null;
  createdBy: User;
  updatedBy: User | null;
}

export interface AccompanyingPeriodWorkEvaluationDocument {
  id: number;
  type: "accompanying_period_work_evaluation_document";
  storedObject: StoredObject;
  title: string;
  createdAt: DateTime | null;
  createdBy: User | null;
  updatedAt: DateTime | null;
  updatedBy: User | null;
  workflows_availables: WorkflowAvailable[];
  workflows: object[];
}

/**
 * Entity types that a user can create through AddPersons component
 */
export type CreatableEntityType = "person" | "thirdparty";

/**
 * Entities that can be search and selected by a user
 */
export type EntityType =
  | CreatableEntityType
  | "user_group"
  | "user"
  | "household";

export type Entities = UserGroup | User | Person | Thirdparty | Household;

export function isEntityHousehold(e: Entities): e is Household {
  return e.type === "household";
}

export type EntitiesOrMe = "me" | Entities;

// Type guards to discriminate Suggestions by their result kind
export function isSuggestionForUserGroup(
  s: Suggestion,
): s is Suggestion & { result: UserGroup } {
  return (s as any)?.result?.type === "user_group";
}

export function isSuggestionForUser(
  s: Suggestion,
): s is Suggestion & { result: User } {
  return (s as any)?.result?.type === "user";
}

export function isSuggestionForPerson(
  s: Suggestion,
): s is Suggestion & { result: Person } {
  return (s as any)?.result?.type === "person";
}

export function isSuggestionForThirdParty(
  s: Suggestion,
): s is Suggestion & { result: Thirdparty } {
  return (s as any)?.result?.type === "thirdparty";
}

export function isSuggestionForHousehold(
  s: Suggestion,
): s is Suggestion & { result: Household } {
  return (s as any)?.result?.type === "household";
}

export type AddPersonResult = Entities & {
  parent?: Entities | null;
};

export interface Suggestion {
  key: string;
  relevance: number;
  result: Entities;
}
export interface SearchPagination {
  first: number;
  items_per_page: number;
  next: number | null;
  previous: number | null;
  more: boolean;
}

export interface Search {
  count: number;
  pagination: SearchPagination;
  results: { relevance: number; result: Entities }[];
}

export interface SearchOptions {
  uniq: boolean;
  /** @deprecated */
  type: EntityType[];
  priority: number | null;
  button: {
    size: string;
    class: string;
    type: string;
    display: string;
  };
}

type PersonIdentifierPresence =
  | "NOT_EDITABLE"
  | "ON_EDIT"
  | "ON_CREATION"
  | "REQUIRED";

export interface PersonIdentifierWorker {
  type: "person_identifier_worker";
  definition_id: number;
  engine: string;
  label: TranslatableString;
  isActive: boolean;
  presence: PersonIdentifierPresence;
}

export class MakeFetchException extends Error {
  sta: number;
  txt: string;
  violations: unknown | null;

  constructor(txt: string, sta: number, violations: unknown | null = null) {
    super(txt);
    this.name = "ValidationException";
    this.sta = sta;
    this.txt = txt;
    this.violations = violations;
    Object.setPrototypeOf(this, MakeFetchException.prototype);
  }
}
