import {
    GenericDoc,
    isGenericDocWithStoredObject,
} from "ChillDocStoreAssets/types/generic_doc";
import { StoredObject, StoredObjectStatus } from "ChillDocStoreAssets/types";
import { Person } from "../../../ChillPersonBundle/Resources/public/types";

export interface DateTime {
    datetime: string;
    datetime8601: string;
}

export interface Civility {
    id: number;
    // TODO
}

export interface Job {
    id: number;
    type: "user_job";
    label: {
        fr: string; // could have other key. How to do that in ts ?
    };
}

export interface Center {
    id: number;
    type: "center";
    name: string;
}

export interface Scope {
    id: number;
    type: "scope";
    name: {
        fr: string;
    };
}

export interface ResultItem<T> {
    result: T;
    relevance: number;
}

export interface User {
    type: "user";
    id: number;
    username: string;
    text: string;
    text_without_absence: string;
    email: string;
    user_job: Job;
    label: string;
    // todo: mainCenter; mainJob; etc..
}

export interface UserGroup {
    type: "user_group";
    id: number;
    label: TranslatableString;
    backgroundColor: string;
    foregroundColor: string;
    excludeKey: string;
    text: string;
}

export type UserGroupOrUser = User | UserGroup;

export interface UserAssociatedInterface {
    type: "user";
    id: number;
}

export type TranslatableString = Record<string, string>;

export interface Postcode {
    id: number;
    name: string;
    code: string;
    center: Point;
}

export interface Point {
    type: "Point";
    coordinates: [lat: number, lon: number];
}

export interface Country {
    id: number;
    name: TranslatableString;
    code: string;
}

export type AddressRefStatus = "match" | "to_review" | "reviewed";

export interface Address {
    type: "address";
    address_id: number;
    text: string;
    street: string;
    streetNumber: string;
    postcode: Postcode;
    country: Country;
    floor: string | null;
    corridor: string | null;
    steps: string | null;
    flat: string | null;
    buildingName: string | null;
    distribution: string | null;
    extra: string | null;
    confidential: boolean;
    lines: string[];
    addressReference: AddressReference | null;
    validFrom: DateTime;
    validTo: DateTime | null;
    point: Point | null;
    refStatus: AddressRefStatus;
    isNoAddress: boolean;
}

export interface AddressWithPoint extends Address {
    point: Point;
}

export interface AddressReference {
    id: number;
    createdAt: DateTime | null;
    deletedAt: DateTime | null;
    municipalityCode: string;
    point: Point;
    postcode: Postcode;
    refId: string;
    source: string;
    street: string;
    streetNumber: string;
    updatedAt: DateTime | null;
}

export interface SimpleGeographicalUnit {
    id: number;
    layerId: number;
    unitName: string;
    unitRefId: string;
}

export interface GeographicalUnitLayer {
    id: number;
    name: TranslatableString;
    refId: string;
}

export interface Location {
    type: "location";
    id: number;
    active: boolean;
    address: Address | null;
    availableForUsers: boolean;
    createdAt: DateTime | null;
    createdBy: User | null;
    updatedAt: DateTime | null;
    updatedBy: User | null;
    email: string | null;
    name: string;
    phonenumber1: string | null;
    phonenumber2: string | null;
    locationType: LocationType;
}

export interface LocationAssociated {
    type: "location";
    id: number;
}

export interface LocationType {
    type: "location-type";
    id: number;
    active: boolean;
    addressRequired: "optional" | "required";
    availableForUsers: boolean;
    editableByUsers: boolean;
    contactData: "optional" | "required";
    title: TranslatableString;
}

export interface NewsItemType {
    id: number;
    title: string;
    content: string;
    startDate: DateTime;
    endDate: DateTime | null;
}

export interface WorkflowAvailable {
    name: string;
    text: string;
}

export interface WorkflowAttachment {
    id: number;
    relatedGenericDocKey: string;
    relatedGenericDocIdentifiers: object;
    createdAt: DateTime | null;
    createdBy: User | null;
    updatedAt: DateTime | null;
    updatedBy: User | null;
    genericDoc: null | GenericDoc;
}

export type AttachmentWithDocAndStored = WorkflowAttachment & {
    genericDoc: GenericDoc & { storedObject: StoredObject };
};

export function isAttachmentWithDocAndStored(
    a: WorkflowAttachment,
): a is AttachmentWithDocAndStored {
    return (
        isWorkflowAttachmentWithGenericDoc(a) &&
        isGenericDocWithStoredObject(a.genericDoc)
    );
}

export function isWorkflowAttachmentWithGenericDoc(
    attachment: WorkflowAttachment,
): attachment is WorkflowAttachment & { genericDoc: GenericDoc } {
    return attachment.genericDoc !== null;
}

export interface Workflow {
    name: string;
    text: string;
}

export interface EntityWorkflowStep {
    type: "entity_workflow_step";
    id: number;
    comment: string;
    currentStep: StepDefinition;
    isFinal: boolean;
    isFreezed: boolean;
    isFinalized: boolean;
    transitionPrevious: Transition | null;
    transitionAfter: Transition | null;
    previousId: number | null;
    nextId: number | null;
    transitionPreviousBy: User | null;
    transitionPreviousAt: DateTime | null;
}

export interface Transition {
    name: string;
    text: string;
    isForward: boolean;
}

export interface StepDefinition {
    name: string;
    text: string;
}

export interface EntityWorkflow {
    type: "entity_workflow";
    id: number;
    relatedEntityClass: string;
    relatedEntityId: number;
    workflow: Workflow;
    currentStep: EntityWorkflowStep;
    steps: EntityWorkflowStep[];
    datas: WorkflowData;
    title: string;
    isOnHoldAtCurrentStep: boolean;
    _permissions: {
        CHILL_MAIN_WORKFLOW_ATTACHMENT_EDIT: boolean;
    };
}

export interface WorkflowData {
    persons: Person[];
}

export interface ExportGeneration {
    id: string;
    type: "export_generation";
    exportAlias: string;
    createdBy: User | null;
    createdAt: DateTime | null;
    status: StoredObjectStatus;
    storedObject: StoredObject;
}

export interface PrivateCommentEmbeddable {
    comments: Record<number, string>;
}

/**
 * Possible states for the WaitingScreen Component.
 */
export type WaitingScreenState = "pending" | "failure" | "stopped" | "ready";
