import { TimeTrackingEntryMessage } from '../../../../../grpc/generated/exposed/humand/timetracking/v1/timetracking_entries_service';
import {
    DepartmentMemberResponse,
    FaceClockResponse,
    FaceSearchResultResponse,
    FaceSearchResultErrorCause as GrpcFaceSearchResultErrorCause,
    UserBasicDataResponse,
} from '../../../../../grpc/generated/exposed/humand/timetracking/v1/timetracking_kiosk_service';
import { FaceSearchResult } from '../../../../facialRecognition/business/interfaces/faceSearchResult';
import { FaceSearchResultErrorCause } from '../../../../facialRecognition/business/interfaces/faceSearchResultErrorCause';
import { UserBasicDataDTO } from '../../../presentation/dtos/userBasicDataDTO';
import { FaceClockResult } from '../../interfaces/kiosk/faceClockResult';
import { TimeTrackingEntry } from '../../models/timeTrackingEntry';

const mapCause = (cause: FaceSearchResultErrorCause): GrpcFaceSearchResultErrorCause => {
    const causeMap: Record<FaceSearchResultErrorCause, GrpcFaceSearchResultErrorCause> = {
        [FaceSearchResultErrorCause.ERROR]: GrpcFaceSearchResultErrorCause.FACE_SEARCH_RESULT_ERROR_CAUSE_ERROR,
        [FaceSearchResultErrorCause.MATCH]: GrpcFaceSearchResultErrorCause.FACE_SEARCH_RESULT_ERROR_CAUSE_MATCH,
        [FaceSearchResultErrorCause.MULTIPLE_FACES_FOUND]: GrpcFaceSearchResultErrorCause.FACE_SEARCH_RESULT_ERROR_CAUSE_MULTIPLE_FACES_FOUND,
        [FaceSearchResultErrorCause.NO_EXTERNAL_IMAGE_ID_FOUND]:
            GrpcFaceSearchResultErrorCause.FACE_SEARCH_RESULT_ERROR_CAUSE_NO_EXTERNAL_IMAGE_ID_FOUND,
        [FaceSearchResultErrorCause.NO_FACES_FOUND]: GrpcFaceSearchResultErrorCause.FACE_SEARCH_RESULT_ERROR_CAUSE_NO_FACES_FOUND,
        [FaceSearchResultErrorCause.NO_MATCHES_FOUND]: GrpcFaceSearchResultErrorCause.FACE_SEARCH_RESULT_ERROR_CAUSE_NO_MATCHES_FOUND,
        [FaceSearchResultErrorCause.SIMILARITY_THRESHOLD_NOT_PASSED]:
            GrpcFaceSearchResultErrorCause.FACE_SEARCH_RESULT_ERROR_CAUSE_SIMILARITY_THRESHOLD_NOT_PASSED,
    };
    return causeMap[cause] ?? GrpcFaceSearchResultErrorCause.FACE_SEARCH_RESULT_ERROR_CAUSE_UNSPECIFIED;
};

const mapDepartment = (department: { id: number; name: string } | null | undefined): DepartmentMemberResponse | undefined => {
    if (!department) return undefined;
    return {
        id: department.id,
        name: department.name,
    };
};

export const mapUserBasicData = (user: UserBasicDataDTO): UserBasicDataResponse => {
    return {
        department: mapDepartment(user.department),
        email: undefinedIfNull(user.email),
        employeeInternalId: user.employeeInternalId,
        firstName: user.firstName,
        id: user.id,
        lastName: user.lastName,
        profilePicture: undefinedIfNull(user.profilePicture),
    };
};

const mapSearchResult = (result: FaceSearchResult): FaceSearchResultResponse => {
    return {
        cause: mapCause(result.cause),
        extraInfo: undefinedIfNull(result.extraInfo),
        found: result.found,
        matchedUser: result.matchedUser ? mapUserBasicData(result.matchedUser) : undefined,
        multipleFacesMatchedUsers: result.multipleFacesMatchedUsers?.filter((user) => user !== null).map((user) => mapUserBasicData(user!)) ?? [],
    };
};

const mapTimeTrackingEntry = (entry: TimeTrackingEntry | null): TimeTrackingEntryMessage | undefined => {
    if (!entry) return undefined;
    return {
        comment: undefinedIfNull(entry.comment),
        createdAt: undefinedIfNull(entry.createdAt),
        createdBy: undefinedIfNull(entry.createdBy),
        deletedBy: undefinedIfNull(entry.deletedBy),
        entryId: entry.id.toString(),
        eventTime: undefinedIfNull(entry.eventTime),
        facialRecognitionSkipped: undefinedIfNull(entry.facialRecognitionSkipped),
        instanceId: entry.instanceId!,
        isRemoteWork: entry.isRemoteWork || false,
        kioskId: undefinedIfNull(entry.kioskId),
        latitude: undefinedIfNull(entry.location?.latitude),
        location: undefinedIfNull(entry.location),
        locationIncidence: undefinedIfNull(entry.locationIncidence),
        longitude: undefinedIfNull(entry.location?.longitude),
        siteId: undefinedIfNull(entry.siteId),
        source: entry.source,
        summaryId: undefinedIfNull(entry.summaryId),
        time: entry.time,
        type: entry.type,
        updatedAt: undefinedIfNull(entry.updatedAt),
        updatedBy: undefinedIfNull(entry.updatedBy),
        userId: entry.userId,
    };
};

export const mapFaceClockResultToGrpcResponse = (result: FaceClockResult): FaceClockResponse => {
    return {
        searchResult: mapSearchResult(result.searchResult),
        timeTrackingEntry: mapTimeTrackingEntry(result.timeTrackingEntry),
    };
};

const undefinedIfNull = <T>(value: T | null | undefined): T | undefined => (value === null ? undefined : value);
