import ipih

from enum import Enum
from collections import namedtuple
from dataclasses import dataclass, field
from datetime import datetime, timedelta, date
from typing import Any, Tuple, List, Callable, TypeVar, Generic, TypeAlias

strdict: TypeAlias = dict[str, Any]
nbool: TypeAlias = bool | None

@dataclass
class Host:
    name: str
    aliases: str | tuple[str, ...] | None = None
    ip: str | None = None
    description: str | None = None

    @property
    def alias(self) -> str:
        if isinstance(self.aliases, str):
            return self.aliases
        return (
            self.aliases[0]
            if self.aliases is not None and len(self.aliases) > 0
            else self.name
        )


@dataclass
class ZabbixHost:
    id: str | None = None
    name: str | None = None
    host: str | None = None


@dataclass
class IOTDevice:
    name: str | None = None
    id: str | None = None
    key: str | None = None
    mac: str | None = None
    uuid: str | None = None
    sn: str | None = None
    category: str | None = None
    product_name: str | None = None
    product_id: str | None = None
    biz_type: int | None = None


@dataclass
class IOTDeviceStatusProperty:
    code: str | None = None
    name: str | None = None
    type: str | None = None
    unit: str | None = None


@dataclass
class IOTDeviceStatusIntegerProperty(IOTDeviceStatusProperty):

    min: int | float | None = None
    max: int | float | None = None
    scale: int | float | None = None
    step: int | float | None = None


"""
@dataclass
class IOTDeviceStatusProperty:
    code: str | None = None
    name: str | None = None
    type: str | None = None
    values: tuple[IOTDeviceStatusPropertyValue, ...] | None = None
"""


@dataclass
class IOTDeviceStatusValue:
    code: str | None = None
    value: Any = None


@dataclass
class IOTDeviceStatus:
    timestamp: int = 0
    values: tuple[IOTDeviceStatusValue, ...] | None = None


@dataclass
class ZabbixMetricsValue:
    value: Any | None = None
    clock: datetime | int | None = None


@dataclass
class ZabbixMetrics:
    itemid: int | None = None
    type: int = 0
    snmp_oid: str | None = None
    hostid: int = 0
    name: str | None = None
    key_: str | None = None
    delay: str | None = None
    history: str | None = None
    trends: str | None = None
    status: int = 0
    value_type: int = 0
    trapper_hosts: tuple[str, ...] | None = None
    units: str | None = None
    formula: str | None = None
    logtimefmt: str | None = None
    templateid: int = 0
    valuemapid: int = 0
    params: tuple[str, ...] | None = None
    ipmi_sensor: str | None = None
    flags: int = 0
    interfaceid: int = 0
    description: str | None = None
    inventory_link: int = 0
    lifetime: str | None = None
    evaltype: int = 0
    jmx_endpoint: str | None = None
    master_itemid: int = 0
    timeout: str | None = None
    url: str | None = None
    query_fields: tuple[str, ...] | None = None
    posts: str | None = None
    status_codes: int = 0
    follow_redirects: int = 0
    lastclock: datetime | None = None
    lastvalue: Any = None
    prevvalue: Any = None


@dataclass
class PasswordSettings:
    length: int
    special_characters: str
    order_list: list[str]
    special_characters_count: int
    alphabets_lowercase_count: int
    alphabets_uppercase_count: int
    digits_count: int = 1
    shuffled: bool = False


@dataclass
class NameCaption:
    name: str | None
    caption: str | None = None


@dataclass
class NameCaptionDescription(NameCaption):
    description: str | None = None


@dataclass
class OrderedNameCaptionDescription(NameCaptionDescription):
    order: int | None = None


@dataclass
class IconedOrderedNameCaptionDescription(OrderedNameCaptionDescription):
    icon: str | None = None


@dataclass
class ParamItem(NameCaptionDescription):
    optional: bool = False

    visible: bool = True
    saved: bool = True
    key: bool = False

    def configurate(
        self,
        visible: bool | None = None,
        saved: bool | None = None,
        key: bool | None = None,
    ) -> Any:
        result: ParamItem = ParamItem(
            self.name, self.caption, self.description, self.optional
        )
        if visible is not None:
            result.visible = visible
        if saved is not None:
            result.saved = saved
        if key is not None:
            result.key = key
        return result


@dataclass
class FieldItem:
    name: str | None = None
    caption: str | None = None
    visible: bool = True
    class_type: Any | None = None
    default_value: str | None = None
    data_formatter: str = "{data}"


class FieldItemList:
    list: list[FieldItem]

    def copy_field_item(self, value: FieldItem) -> FieldItem:
        return FieldItem(
            value.name,
            value.caption,
            value.visible,
            value.class_type,
            value.default_value,
            value.data_formatter,
        )

    def __init__(self, *args):
        self.list = []
        arg_list = list(args)
        for arg_item in arg_list:
            if isinstance(arg_item, FieldItem):
                item: FieldItem = self.copy_field_item(arg_item)
                self.list.append(item)
            elif isinstance(arg_item, FieldItemList):
                for item in arg_item.list:
                    self.list.append(self.copy_field_item(item))
            elif isinstance(arg_item, list):
                self.list.extend(arg_item)

    def get_list(self) -> list[FieldItem]:
        return self.list

    def get_item_and_index_by_name(self, value: str) -> Tuple[FieldItem, int]:
        index: int = -1
        result: FieldItem | None = None
        for item in self.list:
            index += 1
            if item.name == value:
                result = item
                break
        return result, -1 if result is None else index

    def get_item_by_name(self, value: str) -> FieldItem:
        result, _ = self.get_item_and_index_by_name(value)
        return result

    def position(self, name: str, position: int):
        _, index = self.get_item_and_index_by_name(name)
        if index != -1:
            self.list.insert(position, self.list.pop(index))
        return self

    def get_name_list(self):
        return list(map(lambda item: str(item.name), self.list))

    def get_caption_list(self):
        return list(
            map(lambda x: str(x.caption), filter(lambda y: y.visible, self.list))
        )

    def visible(self, name: str, value: bool):
        item, _ = self.get_item_and_index_by_name(name)
        if item is not None:
            item.visible = value
        return self

    def caption(self, name: str, value: bool):
        item, _ = self.get_item_and_index_by_name(name)
        if item is not None:
            item.caption = value
        return self

    def length(self) -> int:
        return len(self.list)


T = TypeVar("T")
R = TypeVar("R")


@dataclass
class Result(Generic[T]):
    fields: FieldItemList | None = None
    data: T | None = None

    def __len__(self):
        return len(self.data)

    def __iadd__(self, value):
        self.data = self.data or []
        if (
            isinstance(value, Result)
            and isinstance(self.data, list)
            and isinstance(value.data, list)
        ):
            self.data += value.data
        return self

    def __add__(self, value):
        if (
            isinstance(value, Result)
            and isinstance(self.data, list)
            and isinstance(value.data, list)
        ):
            self.data += value.data
        return self


@dataclass
class FullName:
    last_name: str = ""
    first_name: str = ""
    middle_name: str = ""

    def as_list(self) -> list[str]:
        return [self.last_name, self.first_name, self.middle_name]


@dataclass
class UserBase:
    name: str | None = None
    description: str | None = None
    distinguishedName: str | None = None


@dataclass
class User(UserBase):
    samAccountName: str | None = None
    mail: str | None = None
    telephoneNumber: str | None = None
    userAccountControl: int | None = None
    
    @property
    def login(self) -> str:
        return self.samAccountName


Rect = namedtuple("Rect", ["left", "top", "width", "height"])


@dataclass
class IndicationDevice:
    name: str | None = None
    description: str | None = None
    ip_address: tuple[str, int] | None = None


@dataclass
class MailboxInfo:
    timestamp: datetime | None = None
    last_uid: str | None = None


@dataclass
class NewMailMessage:
    mailbox_address: str | None = None
    subject: str | None = None
    text: str | None = None
    from_: str | None = None


@dataclass
class RecipientWaitingForInput:
    group_name: str | None = None
    timeout: int | None = None
    recipient: str | None = None
    timestamp: datetime | None = None


@dataclass
class BarcodeInformation:
    data: str | None = None
    type: str | None = None
    rect: Rect | None = None


@dataclass
class EmailInformation:
    email: str | None = None
    person_pin: int = 0
    person_name: str | None = None


@dataclass
class InaccesableEmailInformation(EmailInformation):
    workstation_name: str | None = None
    registrator_person_name: str | None = None


@dataclass
class CardRegistryFolderPosition:
    ChartFolder: str | None = None
    p_a: int = 0
    p_b: int = 0
    p_c: int = 0


@dataclass
class ActionValue:
    caption: str
    value: str


@dataclass
class LoginPasswordPair:
    login: str | None = None
    password: str | None = None


@dataclass
class OGRN:
    name: str | None = None
    code: str | None = None
    data: dict | None = None


@dataclass
class ComputerDescription:
    name: str | None = None
    properties: int = 0
    description: str | None = None


@dataclass
class Computer(ComputerDescription):
    samAccountName: str | None = None
    accessable: bool | None = None
    
    @property
    def login(self) -> str:
        return self.samAccountName


@dataclass
class Server(Computer):
    pass


@dataclass
class Workstation(Computer):
    pass


@dataclass
class ResourceDescription:
    address: str | None = None
    name: str | None = None
    inaccessibility_check_values: tuple[int, ...] = (2, 20, 15)


@dataclass
class ResourceDescriptionDelegated(ResourceDescription):
    delegator: str | None = None


@dataclass
class ZabbixResourceDescription(ResourceDescription):
    zabbix_host_name: str | None = None

    def get_zabbix_host_name(self) -> str:
        return self.zabbix_host_name or self.address


@dataclass
class ZabbixResourceDescriptionDelegated(
    ZabbixResourceDescription, ResourceDescriptionDelegated
):
    pass


@dataclass
class SiteResourceDescription(ResourceDescription):
    check_certificate_status: bool = False
    check_free_space_status: bool = False
    driver_name: str | None = None
    internal: bool = False


class IResourceStatus:
    pass


@dataclass
class ResourceStatus(ResourceDescription, IResourceStatus):
    accessable: bool | None = None
    inaccessibility_counter: int = 0
    inaccessibility_counter_total: int = 0


@dataclass
class WSResourceStatus(ResourceStatus):
    pass


@dataclass
class ServerResourceStatus(ResourceStatus):
    pass


@dataclass
class DiskStatistics:
    name: str | None = None
    free_space: int | None = None
    size: int | None = None


@dataclass
class DisksStatisticsStatus(IResourceStatus):
    host: str | None = None
    disk_list: list[DiskStatistics] = field(default_factory=list)


@dataclass
class SiteResourceStatus(ResourceStatus, SiteResourceDescription):
    certificate_status: str | None = None
    free_space_status: str | None = None


@dataclass
class MarkPerson:
    FullName: str | None = None
    TabNumber: str | None = None


@dataclass
class MarkPersonDivision(MarkPerson):
    DivisionName: str | None = None
    DivisionID: int | None = None


@dataclass
class TemporaryMark(MarkPerson):
    OwnerTabNumber: str | None = None


@dataclass
class PolibasePersonBase:
    pin: int | None = None
    FullName: str | None = None
    telephoneNumber: str | None = None


@dataclass
class PolibasePerson(PolibasePersonBase):
    Birth: datetime | None = None
    Comment: str | None = None
    ChartFolder: str | None = None
    email: str | None = None
    barcode: str | None = None
    registrationDate: datetime | None = None
    telephoneNumber2: str | None = None
    telephoneNumber3: str | None = None
    telephoneNumber4: str | None = None


@dataclass
class PolibaseNote:
    emailed: str | None = None


@dataclass
class PolibasePersonVisitDS(PolibasePersonBase):
    id: int | None = None
    registrationDate: str | None = None
    beginDate: str | datetime | None = None
    completeDate: str | datetime | None = None
    status: int | None = None
    cabinetID: int | None = None
    doctorID: int | None = None
    doctorFullName: str | None = None
    serviceGroupID: int | None = None
    comment: str | None = None


@dataclass
class CardRegistryFolderStatistics:
    name: str | None = None
    count: int = 0


@dataclass
class PolibasePersonVisitSearchCritery:
    vis_no: Any | None = None
    vis_pat_no: Any | None = None
    vis_pat_name: Any | None = None
    vis_place: Any | None = None
    vis_reg_date: Any | None = None
    vis_date_ps: Any | None = None
    vis_date_pf: Any | None = None
    vis_date_fs: Any | None = None
    vis_date_ff: Any | None = None


@dataclass
class PolibasePersonVisitNotificationDS:
    visitID: int | None = None
    messageID: int | None = None
    type: int | None = None


@dataclass
class EventDS:
    name: str | None = None
    parameters: strdict | None = None
    timestamp: datetime | date | str | int | None = None
    id: int = 0


@dataclass
class Message:
    message: str | None = None
    recipient: str | None = None
    sender: str | None = None
    image_url: str | None = None
    location: tuple[float, float] | None = None


@dataclass
class DelayedMessage(Message):
    date: Any | None = None
    type: int | None = None


@dataclass
class DelayedMessageDS(DelayedMessage):
    id: int | None = None
    status: int | None = None


@dataclass
class MessageSearchCritery:
    id: Any | None = None
    recipient: str | None = None
    date: datetime | str | None = None
    type: Any | None = None
    status: int | None = None
    sender: str | None = None


@dataclass
class PolibasePersonNotificationConfirmation:
    recipient: str | None = None
    sender: str | None = None
    status: int = 0


@dataclass
class PolibasePersonVisitNotification(
    PolibasePersonVisitDS, PolibasePersonVisitNotificationDS
):
    pass


@dataclass
class PolibasePersonVisit(PolibasePersonVisitDS):
    registrationDate: datetime | None = None
    beginDate: datetime | None = None
    completeDate: datetime | None = None
    beginDate2: datetime | None = None
    completeDate2: datetime | None = None
    Comment: str | None = None


@dataclass
class PolibasePersonQuest:
    step: int | None = None
    stepConfirmed: bool | None = None
    timestamp: int | None = None


@dataclass
class PolibasePersonInformationQuest(PolibasePersonBase):
    confirmed: int | None = None
    errors: int | None = None


@dataclass
class PolibasePersonReviewQuest(PolibasePersonQuest):
    beginDate: str | None = None
    completeDate: str | None = None
    grade: int | None = None
    message: str | None = None
    informationWay: int | None = None
    feedbackCallStatus: int | None = None


@dataclass
class MarkGroup:
    GroupName: str | None = None
    GroupID: int | None = None


@dataclass
class Mark(MarkPersonDivision, MarkGroup):
    pID: int | None = None
    mID: int | None = None
    Comment: str | None = None
    telephoneNumber: str | None = None
    type: int | None = None


@dataclass
class PersonDivision:
    id: int | None = None
    name: str | None = None


@dataclass
class TimeTrackingEntity(MarkPersonDivision):
    TimeVal: str | None = None
    Mode: int | None = None


@dataclass
class TimeTrackingResultByDate:
    date: str | None = None
    enter_time: str | None = None
    exit_time: str | None = None
    duration: int | None = None


@dataclass
class TimeTrackingResultByPerson:
    tab_number: str | None = None
    full_name: str | None = None
    duration: int = 0
    list: List[TimeTrackingResultByDate] = field(default_factory=list)


@dataclass
class WhatsAppMessage:
    message: str | None = None
    from_me: bool | None = None
    sender: str | None = None
    recipient: str | None = None
    profile_id: str | None = None
    time: int | None = None
    chatId: str | None = None
    flags: int | None = None
    return_result_key: str | None = None
    args: tuple[Any, ...] | None = None


@dataclass
class WhatsAppMessagePayload:
    title: str
    body: str


@dataclass
class WhatsAppMessageListPayload(WhatsAppMessagePayload):
    btn_text: str
    list: dict


@dataclass
class WhatsAppMessagebButton:
    body: str | None = None
    id: str | None = None


@dataclass
class WhatsAppMessageButtonsPayload(WhatsAppMessagePayload):
    buttons: list[WhatsAppMessagebButton] | None = None


@dataclass
class TimeTrackingResultByDivision:
    name: str
    list: List[TimeTrackingResultByPerson] = field(default_factory=list)


@dataclass
class RobocopyJobDescription:
    name: str | None = None
    start_cron_string: str | None = None
    host: str | None = None
    run_from_system_account: bool = False
    run_with_elevetion: bool = False
    live: bool = False
    exclude: bool = False

    def clone(
        self,
        job_name: str,
        start_cron_string: str | None = None,
        host: str | None = None,
        live: bool | None = None,
        exclude: bool = False,
    ):
        return RobocopyJobDescription(
            job_name,
            start_cron_string,
            host or self.host,
            self.run_from_system_account,
            self.run_with_elevetion,
            self.live if live is None else live,
            self.exclude if exclude is None else exclude,
        )


@dataclass
class RobocopyJobItem(RobocopyJobDescription):
    source: str | None = None
    destination: str | None = None


@dataclass
class RobocopyJobStatus:
    name: str | None = None
    source: str | None = None
    destination: str | None = None
    active: bool = False
    last_started: str | None = None
    last_created: str | None = None
    last_status: int | None = None
    live: bool = False
    pid: int = -1
    exclude: bool = False


@dataclass
class PrinterADInformation:
    driverName: str | None = None
    adminDescription: str | None = None
    description: str | None = None
    portName: str | None = None
    serverName: str | None = None
    name: str | None = None


@dataclass
class IndicationsContainer:
    timestamp: datetime | None = None


@dataclass
class HumidityIndicationsValue:
    humidity: float | None = None


@dataclass
class TemparatureIndicationsValue:
    temperature: float | None = None


@dataclass
class TemperatureAndHumidityIndicationsValue(
    HumidityIndicationsValue, TemparatureIndicationsValue
):
    pass


@dataclass
class ChillerIndicationsValue(TemparatureIndicationsValue):
    indicators: int = 0


@dataclass
class ChillerIndicationsValueContainer(ChillerIndicationsValue, IndicationsContainer):
    pass


@dataclass
class CTIndicationsValue(TemperatureAndHumidityIndicationsValue):
    pass


@dataclass
class CTIndicationsValueContainer(CTIndicationsValue, IndicationsContainer):
    pass


@dataclass
class GKeepItem:
    name: str | None = None
    title: str | None = None
    id: str | None = None


@dataclass
class File:
    title: str | None = None
    text: str | None = None
    id: str | None = None


@dataclass
class Note(File):
    images: list[str] | None = None


@dataclass
class InventoryReportItem:
    name: str | int | None = None
    inventory_number: str | None = None
    row: str | None = None
    quantity: int | None = None
    name_column: int | None = None
    inventory_number_column: int | None = None
    quantity_column: int | None = None


@dataclass
class PrinterStatus:
    ip: str | None = None
    description: str | None = None
    variant: str | None = None
    port: int | None = None
    community: str | None = None
    accessable: bool | None = None


@dataclass
class TimeSeriesStatistics:
    count: int = 0
    values: list[datetime] | None = None
    distance: list[timedelta] | None = None
    min: int | None = None
    max: int | None = None
    avg: int | None = None


@dataclass
class PrinterReport(PrinterStatus):
    name: str | None = None
    model: str | None = None
    serial: int | None = None
    adminDescription: str | None = None
    meta: str | None = None
    printsOverall: int | None = None
    printsColor: int | None = None
    printsMonochrome: int | None = None
    fuserType: int | None = None
    fuserCapacity: int | None = None
    fuserRemaining: int | None = None
    wasteType: int | None = None
    wasteCapacity: int | None = None
    wasteRemaining: int | None = None
    cleanerType: int | None = None
    cleanerCapacity: int | None = None
    cleanerRemaining: int | None = None
    transferType: int | None = None
    transferCapacity: int | None = None
    transferRemaining: int | None = None
    blackTonerType: str | None = None
    blackTonerCapacity: int | None = None
    blackTonerRemaining: int | None = None
    cyanTonerType: int | None = None
    cyanTonerCapacity: int | None = None
    cyanTonerRemaining: int | None = None
    magentaTonerType: int | None = None
    magentaTonerCapacity: int | None = None
    magentaTonerRemaining: int | None = None
    yellowTonerType: int | None = None
    yellowTonerCapacity: int | None = None
    yellowTonerRemaining: int | None = None
    blackDrumType: str | None = None
    blackDrumCapacity: int | None = None
    blackDrumRemaining: int | None = None
    cyanDrumType: int | None = None
    cyanDrumCapacity: int | None = None
    cyanDrumRemaining: int | None = None
    magentaDrumType: int | None = None
    magentaDrumCapacity: int | None = None
    magentaDrumRemaining: int | None = None
    yellowDrumType: int | None = None
    yellowDrumCapacity: int | None = None
    yellowDrumRemaining: int | None = None

    def get_toner(self, color: str) -> int:
        color = color.lower()
        remaining: int
        capacity: int
        if color == "c":
            remaining = self.cyanTonerRemaining
            capacity = self.cyanTonerCapacity
        if color == "m":
            remaining = self.magentaTonerRemaining
            capacity = self.magentaTonerCapacity
        if color == "y":
            remaining = self.yellowTonerRemaining
            capacity = self.yellowTonerCapacity
        if color == "k":
            remaining = self.blackTonerRemaining
            capacity = self.blackTonerCapacity
        try:
            if remaining == -1 or capacity == -1:
                return -1
            if remaining == -404 or capacity == -404:
                return -404
            if remaining == -401 or capacity == -401:
                return -401
            return int(round((int(remaining) / int(capacity)) * 100))
        except:
            return -1

    def get_drum(self, color: str) -> int:
        color = color.lower()
        if color == "c":
            remaining = self.cyanDrumRemaining
            capacity = self.cyanDrumCapacity
        if color == "m":
            remaining = self.magentaDrumRemaining
            capacity = self.magentaDrumCapacity
        if color == "y":
            remaining = self.yellowDrumRemaining
            capacity = self.yellowDrumCapacity
        if color == "k":
            remaining = self.blackDrumRemaining
            capacity = self.blackDrumCapacity
        try:
            if remaining == -1 or capacity == -1:
                return -1
            if remaining == -404 or capacity == -404:
                return -404
            if remaining == -401 or capacity == -401:
                return -401
            return int(round((int(remaining) / int(capacity)) * 100))
        except:
            return -1


@dataclass
class MarkGroupStatistics(MarkGroup):
    Comment: str | None = None
    Count: int | None = None


@dataclass
class EventDescription:
    message: str | Callable[[tuple[Any, ...] | list[Any]], str] | None = None
    channel: Enum | None = None
    flags: int | tuple[Enum, ...] | Enum | None = None
    params: tuple[ParamItem, ...] | None = None


@dataclass
class ActionDescription:
    name: str | None = None
    alias: tuple[str, ...] | None = None
    description: str | None = None
    question: str | None = None
    confirm: bool = True
    silence: bool = False
    parameters_description: str | None = None
    # parameters_default: tuple[str] | None = None
    forcable: bool = False
    forced_description: str | None = None


@dataclass
class ActionWasDone:
    action_description: str | None = None
    action: Enum | str | None = None
    user_name: str | None = None
    user_login: str | None = None
    parameters: list[Any] | None = None
    forced: bool = False


@dataclass
class StorageVariableHolder:
    key_name: str | None = None
    default_value: str | None = None
    description: str | None = None
    auto_init: bool = True
    # only for get
    section: str | None = None


@dataclass
class ExpiredTimestampVariableHolder:
    timestamp: str | None = None
    life_time: str | None = None
    resolver_note: str | None = None


@dataclass
class IntStorageVariableHolder(StorageVariableHolder):
    default_value: int = 0


@dataclass
class VariantableStorageVariable:
    variants: tuple[Any, ...]| None = None


@dataclass
class IntVariantableStorageVariableHolder(
    VariantableStorageVariable, IntStorageVariableHolder
):
    variants: tuple[int, ...] | None = None


@dataclass
class MinIntStorageVariableHolder(IntStorageVariableHolder):
    min_value: int = 0


@dataclass
class IntStorageVariableHolderWithMin(IntStorageVariableHolder):
    min_value: int = 0


@dataclass
class IntListStorageVariableHolder(StorageVariableHolder):
    default_value: list[int] | None = None


@dataclass
class FloatStorageVariableHolder(StorageVariableHolder):
    default_value: float | None = None


@dataclass
class BoolStorageVariableHolder(StorageVariableHolder):
    default_value: bool | None = None


@dataclass
class TimeStorageVariableHolder(StorageVariableHolder):
    default_value: str | None = None


@dataclass
class DateListStorageVariableHolder(StorageVariableHolder):
    default_value: tuple[str, ...] | None = None


@dataclass
class StringListStorageVariableHolder(StorageVariableHolder):
    default_value: tuple[str, ...] | None = None


@dataclass
class PolibaseDocument:
    file_path: str | None = None
    polibase_person_pin: int | None = None
    document_type: str | None = None


@dataclass
class MedicalDirectionDocument:
    number: int | None = None
    date: datetime | None = None
    person_name: str | None = None
    person_ensurence_number: str | None = None
    person_ensurence_agent: str | None = None
    person_birthday: datetime | str | None = None
    research_type: Enum | str | None = None
    research_code: str | None = None
    ogrn_number: str | None = None


@dataclass
class Titled:
    title: str


@dataclass
class ThresholdedText(Titled):
    threshold: float


@dataclass
class PolibaseDocumentDescription(ThresholdedText):
    title_top: int = 0
    title_height: int = 0
    page_count: int = 1


@dataclass
class DocumentDescription(ThresholdedText):
    left: float
    top: float
    right: float
    bottom: float


@dataclass
class MedicalResearchType:
    title_list: tuple[str, ...] | None = None
    alias: str | None = None


@dataclass
class DirectoryInfo:
    value: str | None = None
    confirmed_file_list: list[tuple[str, float]] | None = None
    last_created_file_timestamp: float | None = None


@dataclass
class JournalRecord:
    # from pih.const import JournalType, Tags
    timestamp: datetime | None = None
    applicant_user: User | None = None
    type: Any | None = None
    tag: Any | None = None
    title: str | None = None
    text: str | None = None
    parameters: dict[str, Any] | None = None


@dataclass
class BonusInformation:
    bonus_all: float = 0
    money_all: float = 0
    bonus_spent_all: float = 0
    bonus_active: float = 0
    money_last: float = 0
    bonus_last_spent: float = 0
    bonus_last: float = 0


@dataclass
class WappiStatus:

    app_status: str | None = None
    authorized: bool = False
    authorized_at: str | None = None
    checked_at: str | None = None
    last_activity: float = 0
    logouted_at: str | None = None
    message_count: int = 0
    name: str | None = None
    payment_expired_at: str | None = None
    payment_notification: bool = False
    phone: str | None = None
    profile_id: str | None = None
    proxy: str | None = None
    uuid: str | None = None
    webhook_types: tuple[str, ...] = ()
    webhook_url: str | None = None
    worked_days: int = 0
