package de.assecutor.votianlt.config;

import de.assecutor.votianlt.model.task.*;
import de.assecutor.votianlt.model.task.CommentTask;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.bson.Document;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import org.bson.types.ObjectId;

@Configuration
public class MongoConfig {

    @Bean
    public MongoCustomConversions customConversions() {
        List<Converter<?, ?>> converters = new ArrayList<>();
        converters.add(new DocumentToBaseTaskConverter());
        return new MongoCustomConversions(converters);
    }

    @ReadingConverter
    @Slf4j
    public static class DocumentToBaseTaskConverter implements Converter<Document, BaseTask> {

        @Override
        public BaseTask convert(Document source) {
            // Debug logging to see what's in the document
            log.debug("Converting MongoDB document to BaseTask. Document keys: {}", source.keySet());
            log.debug("Full document content: {}", source.toJson());

            // Use _class field for type discrimination (MongoDB standard)
            String className = source.getString("_class");
            if (className == null) {
                // Fallback to taskType field if _class is not present
                String taskType = source.getString("taskType");
                if (taskType == null) {
                    taskType = source.getString("task_type");
                }
                // Map taskType to class name
                className = mapTaskTypeToClassName(taskType);
            }

            log.debug("Extracted className: '{}' from document", className);

            BaseTask task;
            switch (className) {
            case "de.assecutor.votianlt.model.task.ConfirmationTask":
            case "ConfirmationTask":
                log.debug("Creating ConfirmationTask");
                task = new ConfirmationTask();
                if (source.containsKey("button_text")) {
                    ((ConfirmationTask) task).setButtonText(source.getString("button_text"));
                }
                break;
            case "de.assecutor.votianlt.model.task.SignatureTask":
            case "SignatureTask":
                log.debug("Creating SignatureTask");
                task = new SignatureTask();
                break;
            case "de.assecutor.votianlt.model.task.PhotoTask":
            case "PhotoTask":
                log.debug("Creating PhotoTask");
                task = new PhotoTask();
                if (source.containsKey("min_photo_count")) {
                    ((PhotoTask) task).setMinPhotoCount(source.getInteger("min_photo_count"));
                }
                if (source.containsKey("max_photo_count")) {
                    ((PhotoTask) task).setMaxPhotoCount(source.getInteger("max_photo_count"));
                }
                break;
            case "de.assecutor.votianlt.model.task.TodoListTask":
            case "TodoListTask":
                log.debug("Creating TodoListTask");
                task = new TodoListTask();
                if (source.containsKey("todo_items")) {
                    // Suppressing unchecked cast warning as MongoDB document structure is validated
                    @SuppressWarnings("unchecked")
                    List<String> todoItems = (List<String>) source.get("todo_items");
                    ((TodoListTask) task).setTodoItems(todoItems);
                }
                break;
            case "de.assecutor.votianlt.model.task.BarcodeTask":
            case "BarcodeTask":
                log.debug("Creating BarcodeTask");
                task = new BarcodeTask();
                if (source.containsKey("min_barcode_count")) {
                    ((BarcodeTask) task).setMinBarcodeCount(source.getInteger("min_barcode_count"));
                }
                if (source.containsKey("max_barcode_count")) {
                    ((BarcodeTask) task).setMaxBarcodeCount(source.getInteger("max_barcode_count"));
                }
                break;
            case "de.assecutor.votianlt.model.task.CommentTask":
            case "CommentTask":
                log.debug("Creating CommentTask");
                task = new CommentTask();
                if (source.containsKey("comment_text")) {
                    ((CommentTask) task).setCommentText(source.getString("comment_text"));
                }
                if (source.containsKey("required")) {
                    ((CommentTask) task).setRequired(source.getBoolean("required", false));
                }
                break;
            default:
                log.warn("Unknown className '{}', falling back to ConfirmationTask", className);
                task = new ConfirmationTask(); // fallback
                break;
            }

            // Set common fields
            if (source.containsKey("_id")) {
                task.setId(source.getObjectId("_id"));
            }
            task.setStationId(readObjectId(source, "station_id"));
            task.setJobId(readObjectId(source, "job_id"));
            if (source.containsKey("station_order")) {
                task.setStationOrder(source.getInteger("station_order"));
            }
            if (source.containsKey("task_order")) {
                task.setTaskOrder(source.getInteger("task_order", 0));
            }
            if (source.containsKey("description")) {
                task.setDescription(source.getString("description"));
            }
            if (source.containsKey("optional")) {
                task.setOptional(source.getBoolean("optional", false));
            }
            if (source.containsKey("completed")) {
                task.setCompleted(source.getBoolean("completed", false));
            }
            if (source.containsKey("completed_at") && source.get("completed_at") != null) {
                Object completedAtObj = source.get("completed_at");
                if (completedAtObj instanceof String) {
                    task.setCompletedAt(
                            LocalDateTime.parse((String) completedAtObj, DateTimeFormatter.ISO_LOCAL_DATE_TIME));
                } else if (completedAtObj instanceof java.util.Date) {
                    task.setCompletedAt(((java.util.Date) completedAtObj).toInstant()
                            .atZone(java.time.ZoneId.systemDefault()).toLocalDateTime());
                }
            }
            if (source.containsKey("completed_by")) {
                task.setCompletedBy(source.getString("completed_by"));
            }

            return task;
        }

        private ObjectId readObjectId(Document source, String key) {
            Object value = source.get(key);
            if (value instanceof ObjectId objectId) {
                return objectId;
            }
            if (value instanceof String stringValue && ObjectId.isValid(stringValue)) {
                return new ObjectId(stringValue);
            }
            return null;
        }

        private String mapTaskTypeToClassName(String taskType) {
            if (taskType == null) {
                return "de.assecutor.votianlt.model.task.ConfirmationTask";
            }
            switch (taskType) {
            case "CONFIRMATION":
                return "de.assecutor.votianlt.model.task.ConfirmationTask";
            case "SIGNATURE":
                return "de.assecutor.votianlt.model.task.SignatureTask";
            case "PHOTO":
                return "de.assecutor.votianlt.model.task.PhotoTask";
            case "TODOLIST":
                return "de.assecutor.votianlt.model.task.TodoListTask";
            case "BARCODE":
                return "de.assecutor.votianlt.model.task.BarcodeTask";
            case "COMMENT":
                return "de.assecutor.votianlt.model.task.CommentTask";
            default:
                return "de.assecutor.votianlt.model.task.ConfirmationTask";
            }
        }
    }
}
