package de.assecutor.votianlt.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import de.assecutor.votianlt.model.Job;
import de.assecutor.votianlt.model.JobHistory;
import de.assecutor.votianlt.model.JobHistoryType;
import de.assecutor.votianlt.model.JobStatus;
import de.assecutor.votianlt.repository.JobHistoryRepository;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@Slf4j
public class JobHistoryService {

    private final JobHistoryRepository jobHistoryRepository;
    private final ObjectMapper objectMapper;

    public JobHistoryService(JobHistoryRepository jobHistoryRepository, ObjectMapper objectMapper) {
        this.jobHistoryRepository = jobHistoryRepository;
        this.objectMapper = objectMapper;
    }

    /**
     * Log job creation
     */
    public void logJobCreation(Job job, String createdBy) {
        try {
            JobHistory history = new JobHistory(job.getId(), "Job erstellt",
                    "Neuer Job wurde erstellt: " + (job.getJobNumber() != null ? job.getJobNumber() : "Ohne Nummer"),
                    createdBy, JobHistoryType.CREATE, null, "Job erstellt");

            if (job.getDeliveryCompany() != null) {
                history.setDetails("Kunde: " + job.getDeliveryCompany());
            }

            jobHistoryRepository.save(history);
            log.debug("Job creation logged for job {}", job.getIdAsString());
        } catch (Exception e) {
            log.error("Failed to log job creation for job {}: {}", job.getIdAsString(), e.getMessage());
        }
    }

    /**
     * Log job status change
     */
    public void logStatusChange(Job job, JobStatus oldStatus, JobStatus newStatus, String changedBy) {
        try {
            String description = String.format("Status geändert von %s zu %s", formatStatus(oldStatus),
                    formatStatus(newStatus));

            JobHistory history = new JobHistory(job.getId(), "Status-Änderung", description, changedBy,
                    JobHistoryType.STATUS_CHANGE, oldStatus != null ? oldStatus.toString() : null,
                    newStatus != null ? newStatus.toString() : null);

            jobHistoryRepository.save(history);
            log.debug("Status change logged for job {}: {} -> {}", job.getIdAsString(), oldStatus, newStatus);
        } catch (Exception e) {
            log.error("Failed to log status change for job {}: {}", job.getIdAsString(), e.getMessage());
        }
    }

    /**
     * Log general job update
     */
    public void logJobUpdate(Job oldJob, Job newJob, String changedBy, String reason) {
        try {
            String description = generateUpdateDescription(oldJob, newJob);

            JobHistory history = new JobHistory(newJob.getId(), reason != null ? reason : "Job aktualisiert",
                    description, changedBy, JobHistoryType.UPDATE, serializeJobForComparison(oldJob),
                    serializeJobForComparison(newJob));

            jobHistoryRepository.save(history);
            log.debug("Job update logged for job {}", newJob.getIdAsString());
        } catch (Exception e) {
            log.error("Failed to log job update for job {}: {}", newJob.getIdAsString(), e.getMessage());
        }
    }

    /**
     * Log task completion
     */
    public void logTaskCompletion(ObjectId jobId, String taskType, String taskId, String completedBy) {
        logTaskCompletion(jobId, taskType, taskId, completedBy, null, null);
    }

    /**
     * Log task completion with detailed information and extraData
     */
    public void logTaskCompletion(ObjectId jobId, String taskType, String taskId, String completedBy,
            String taskDisplayName, String extraDataSummary) {
        try {
            String taskName = taskDisplayName != null ? taskDisplayName : taskType;
            String description = String.format("Aufgabe abgeschlossen: %s", taskName);

            if (extraDataSummary != null && !extraDataSummary.isBlank()) {
                description += " - " + extraDataSummary;
            }

            JobHistory history = new JobHistory(jobId, "Aufgabe abgeschlossen", description, completedBy,
                    JobHistoryType.TASK_COMPLETED, "In Bearbeitung", "Abgeschlossen");

            // Detaillierte Informationen in details speichern
            StringBuilder details = new StringBuilder();
            details.append("Task-ID: ").append(taskId);
            details.append(", Task-Typ: ").append(taskType);

            if (taskDisplayName != null && !taskDisplayName.equals(taskType)) {
                details.append(", Name: ").append(taskDisplayName);
            }

            if (extraDataSummary != null && !extraDataSummary.isBlank()) {
                details.append(", Zusatzdaten: ").append(extraDataSummary);
            }

            history.setDetails(details.toString());
            jobHistoryRepository.save(history);
            log.debug("Task completion logged for job {}, task {} with details", jobId.toHexString(), taskId);
        } catch (Exception e) {
            log.error("Failed to log task completion for job {}: {}", jobId.toHexString(), e.getMessage());
        }
    }

    /**
     * Log job assignment
     */
    public void logJobAssignment(Job job, String oldAssignee, String newAssignee, String changedBy) {
        try {
            String description;
            if (oldAssignee == null && newAssignee != null) {
                description = "Job zugewiesen an: " + newAssignee;
            } else if (oldAssignee != null && newAssignee == null) {
                description = "Job-Zuweisung entfernt von: " + oldAssignee;
            } else {
                description = String.format("Job-Zuweisung geändert von %s zu %s", oldAssignee, newAssignee);
            }

            JobHistory history = new JobHistory(job.getId(), "Zuweisung geändert", description, changedBy,
                    JobHistoryType.ASSIGNMENT, oldAssignee, newAssignee);

            jobHistoryRepository.save(history);
            log.debug("Job assignment logged for job {}", job.getIdAsString());
        } catch (Exception e) {
            log.error("Failed to log job assignment for job {}: {}", job.getIdAsString(), e.getMessage());
        }
    }

    /**
     * Log custom event
     */
    public void logCustomEvent(ObjectId jobId, String reason, String description, String changedBy,
            JobHistoryType type) {
        try {
            JobHistory history = new JobHistory(jobId, reason, description, changedBy, type, null, null);
            jobHistoryRepository.save(history);
            log.debug("Custom event logged for job {}: {}", jobId.toHexString(), reason);
        } catch (Exception e) {
            log.error("Failed to log custom event for job {}: {}", jobId.toHexString(), e.getMessage());
        }
    }

    /**
     * Get job history
     */
    public List<JobHistory> getJobHistory(ObjectId jobId) {
        return jobHistoryRepository.findByJobIdOrderByTimestampDesc(jobId);
    }

    /**
     * Get job history count
     */
    public long getJobHistoryCount(ObjectId jobId) {
        return jobHistoryRepository.countByJobId(jobId);
    }

    // Helper methods

    private String formatStatus(JobStatus status) {
        if (status == null)
            return "Unbekannt";

        return switch (status) {
        case CREATED -> "Erstellt";
        case IN_PROGRESS -> "In Bearbeitung";
        case PICKUP_SCHEDULED -> "Abholung geplant";
        case PICKED_UP -> "Abgeholt";
        case IN_TRANSIT -> "Unterwegs";
        case DELIVERED -> "Zugestellt";
        case COMPLETED -> "Abgeschlossen";
        case CANCELLED -> "Storniert";
        default -> status.toString();
        };
    }

    private String generateUpdateDescription(Job oldJob, Job newJob) {
        StringBuilder description = new StringBuilder("Job-Daten aktualisiert");

        if (oldJob == null) {
            return description.toString();
        }

        // Check for specific field changes
        boolean hasChanges = false;

        if (!equals(oldJob.getDeliveryCompany(), newJob.getDeliveryCompany())) {
            description.append(" - Kunde");
            hasChanges = true;
        }

        if (!equals(oldJob.getPickupCity(), newJob.getPickupCity())
                || !equals(oldJob.getDeliveryCity(), newJob.getDeliveryCity())) {
            if (hasChanges)
                description.append(",");
            description.append(" - Orte");
            hasChanges = true;
        }

        if (!equals(oldJob.getRemark(), newJob.getRemark())) {
            if (hasChanges)
                description.append(",");
            description.append(" - Bemerkung");
            hasChanges = true;
        }

        return description.toString();
    }

    private boolean equals(Object a, Object b) {
        return (a == null && b == null) || (a != null && a.equals(b));
    }

    private String serializeJobForComparison(Job job) {
        try {
            // Only serialize relevant fields for comparison
            return objectMapper.writeValueAsString(job);
        } catch (Exception e) {
            return "Serialization failed";
        }
    }
}