package de.assecutor.votianlt.service;

import de.assecutor.votianlt.model.AppUser;
import de.assecutor.votianlt.model.Job;
import de.assecutor.votianlt.model.User;
import de.assecutor.votianlt.repository.AppUserRepository;
import de.assecutor.votianlt.repository.JobRepository;
import de.assecutor.votianlt.repository.UserRepository;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
@RequiredArgsConstructor
@Slf4j
public class EmailService {
    private final UserRepository userRepository;
    private final JobRepository jobRepository;
    private final TaskAssignmentService taskAssignmentService;
    private final AppUserRepository appUserRepository;
    private final JavaMailSender mailSender;

    @Value("${spring.mail.username}")
    private String smtpUsername;

    @Async
    public void sendTaskCompletionNotification(ObjectId jobId, String taskType, String taskId, String completedBy) {
        try {
            // Load job to get context information
            Optional<Job> jobOpt = jobRepository.findById(jobId);
            if (jobOpt.isEmpty()) {
                log.warn("Job not found for task completion notification: {}", jobId);
                return;
            }
            Job job = jobOpt.get();

            // Find the app user who completed the task
            Optional<User> userOpt = userRepository.findById(new ObjectId(job.getCreatedBy()));
            if (userOpt.isEmpty()) {
                log.warn("User not found for task completion notification: {}", job.getId());
                return;
            }
            User user = userOpt.get();

            // Check if user has email
            if (user.getEmail() == null || user.getEmail().isBlank()) {
                log.warn("User has no email address for task completion notification: {}", user.getId());
                return;
            }

            String completedByName = resolveCompletedByName(job, completedBy);

            // Send email
            sendEmail(user, job, taskType, completedByName);
            log.info("Task completion notification sent to {} for job {} task {}", user.getEmail(), job.getJobNumber(),
                    taskId);

        } catch (Exception e) {
            log.error("Failed to send task completion notification for job {} task {}: {}", jobId, taskId,
                    e.getMessage(), e);
        }
    }

    private void sendEmail(User user, Job job, String taskType, String completedByName) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(smtpUsername);
        message.setTo(user.getEmail());
        message.setSubject(
                "Aufgabe abgeschlossen - " + (job.getJobNumber() != null ? job.getJobNumber() : "Job " + job.getId()));

        String fullName = buildFullName(user);
        String taskTypeName = getTaskTypeDisplayName(taskType);

        StringBuilder body = new StringBuilder();
        body.append("Hallo ").append(fullName).append(",\n\n");
        body.append("eine Aufgabe wurde von ").append(completedByName).append(" abgeschlossen:\n\n");
        body.append("Job: ").append(job.getJobNumber() != null ? job.getJobNumber() : "Unbekannt").append("\n");
        if (job.getDeliveryCompany() != null) {
            body.append("Kunde: ").append(job.getDeliveryCompany()).append("\n");
        }
        body.append("Aufgabe: ").append(taskTypeName).append("\n");
        body.append("Abgeschlossen von: ").append(completedByName).append("\n\n");

        String deliveryCities = job.getDeliveryCitiesDisplay();
        if (job.getPickupCity() != null || deliveryCities != null) {
            body.append("Route: ");
            if (job.getPickupCity() != null) {
                body.append(job.getPickupCity());
            }
            if (job.getPickupCity() != null && deliveryCities != null) {
                body.append(" → ");
            }
            if (deliveryCities != null) {
                body.append(deliveryCities);
            }
            body.append("\n\n");
        }

        body.append("Mit freundlichen Grüßen,\n");
        body.append("Ihr Votianlt-System");

        message.setText(body.toString());
        mailSender.send(message);
    }

    private String buildFullName(User user) {
        StringBuilder name = new StringBuilder();
        if (user.getTitle() != null && !user.getTitle().isBlank()) {
            name.append(user.getTitle()).append(" ");
        }
        if (user.getFirstname() != null && !user.getFirstname().isBlank()) {
            name.append(user.getFirstname()).append(" ");
        }
        if (user.getName() != null && !user.getName().isBlank()) {
            name.append(user.getName());
        }
        String fullName = name.toString().trim();
        return fullName.isEmpty() ? "Benutzer" : fullName;
    }

    private String buildAppUserName(AppUser appUser) {
        StringBuilder name = new StringBuilder();
        if (appUser.getVorname() != null && !appUser.getVorname().isBlank()) {
            name.append(appUser.getVorname()).append(" ");
        }
        if (appUser.getNachname() != null && !appUser.getNachname().isBlank()) {
            name.append(appUser.getNachname());
        }

        String fullName = name.toString().trim();
        if (!fullName.isEmpty()) {
            return fullName;
        }
        if (appUser.getBezeichnung() != null && !appUser.getBezeichnung().isBlank()) {
            return appUser.getBezeichnung().trim();
        }
        if (appUser.getEmail() != null && !appUser.getEmail().isBlank()) {
            return appUser.getEmail().trim();
        }
        return "App-Benutzer";
    }

    private String resolveCompletedByName(Job job, String completedBy) {
        Optional<AppUser> assignedAppUser = findAppUserById(job != null ? job.getAppUser() : null);
        if (assignedAppUser.isPresent()) {
            return buildAppUserName(assignedAppUser.get());
        }

        if (completedBy != null && !completedBy.isBlank() && !"Unknown".equalsIgnoreCase(completedBy)) {
            Optional<AppUser> completingAppUser = findAppUserById(completedBy);
            if (completingAppUser.isPresent()) {
                return buildAppUserName(completingAppUser.get());
            }
            return completedBy;
        }

        return "App-Benutzer";
    }

    private Optional<AppUser> findAppUserById(String appUserId) {
        if (appUserId == null || appUserId.isBlank()) {
            return Optional.empty();
        }

        try {
            return appUserRepository.findById(new ObjectId(appUserId));
        } catch (IllegalArgumentException e) {
            return Optional.empty();
        }
    }

    private String getTaskTypeDisplayName(String taskType) {
        if (taskType == null)
            return "Unbekannte Aufgabe";

        return switch (taskType.toUpperCase()) {
        case "PHOTO" -> "Foto-Aufgabe";
        case "SIGNATURE" -> "Unterschrift";
        case "BARCODE" -> "Barcode scannen";
        case "CONFIRMATION" -> "Bestätigung";
        case "TODO_LIST" -> "Checkliste";
        case "COMMENT" -> "Kommentar";
        default -> taskType;
        };
    }

    @Async
    public void sendJobCompletionNotification(ObjectId jobId, String completedBy) {
        try {
            // Load job
            Optional<Job> jobOpt = jobRepository.findById(jobId);
            if (jobOpt.isEmpty()) {
                log.warn("Job not found for completion notification: {}", jobId);
                return;
            }
            Job job = jobOpt.get();

            // Find the app user who completed the last task
            Optional<User> userOpt = userRepository.findById(new ObjectId(job.getCreatedBy()));
            if (userOpt.isEmpty()) {
                log.warn("User not found for job completion notification: {}", completedBy);
                return;
            }
            User user = userOpt.get();

            // Check if user has email
            if (user.getEmail() == null || user.getEmail().isBlank()) {
                log.warn("User has no email address for job completion notification: {}", user.getId());
                return;
            }

            String completedByName = resolveCompletedByName(job, completedBy);

            // Send job completion email
            sendJobCompletionEmail(user, job, completedByName);
            log.info("Job completion notification sent to {} for job {}", user.getEmail(), job.getJobNumber());

        } catch (Exception e) {
            log.error("Failed to send job completion notification for job {}: {}", jobId, e.getMessage(), e);
        }
    }

    private void sendJobCompletionEmail(User user, Job job, String completedByName) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(smtpUsername);
        message.setTo(user.getEmail());
        message.setSubject(
                "Job abgeschlossen - " + (job.getJobNumber() != null ? job.getJobNumber() : "Job " + job.getId()));

        String fullName = buildFullName(user);

        // Count completed tasks
        var allTasks = taskAssignmentService.findTasksForJob(job);
        int taskCount = allTasks.size();

        StringBuilder body = new StringBuilder();
        body.append("Hallo ").append(fullName).append(",\n\n");
        body.append("alle Aufgaben für den folgenden Job wurden erfolgreich abgeschlossen:\n\n");
        body.append("Job: ").append(job.getJobNumber() != null ? job.getJobNumber() : "Unbekannt").append("\n");
        if (job.getDeliveryCompany() != null) {
            body.append("Kunde: ").append(job.getDeliveryCompany()).append("\n");
        }

        String deliveryCities = job.getDeliveryCitiesDisplay();
        if (job.getPickupCity() != null || deliveryCities != null) {
            body.append("Route: ");
            if (job.getPickupCity() != null) {
                body.append(job.getPickupCity());
            }
            if (job.getPickupCity() != null && deliveryCities != null) {
                body.append(" → ");
            }
            if (deliveryCities != null) {
                body.append(deliveryCities);
            }
            body.append("\n");
        }

        body.append("Anzahl erledigter Aufgaben: ").append(taskCount).append("\n");
        body.append("Abgeschlossen von: ").append(completedByName).append("\n\n");

        body.append("Der Job ist nun vollständig erledigt und kann weiterverarbeitet werden.\n\n");
        body.append("Mit freundlichen Grüßen,\n");
        body.append("Ihr Votianlt-System");

        message.setText(body.toString());
        mailSender.send(message);
    }

    @Async
    public void sendJobCreationNotification(ObjectId jobId, String createdBy) {
        try {
            // Load job
            Optional<Job> jobOpt = jobRepository.findById(jobId);
            if (jobOpt.isEmpty()) {
                log.warn("Job not found for creation notification: {}", jobId);
                return;
            }
            Job job = jobOpt.get();

            // Find the user who created the job (using createdBy as User ID string)
            ObjectId createdByUserId;
            try {
                createdByUserId = new ObjectId(createdBy);
            } catch (IllegalArgumentException e) {
                log.warn("Invalid createdBy format for job creation notification: {}", createdBy);
                return;
            }

            Optional<User> userOpt = userRepository.findById(createdByUserId);
            if (userOpt.isEmpty()) {
                log.warn("User not found for job creation notification: {}", createdBy);
                return;
            }
            User user = userOpt.get();

            // Check if user has email
            if (user.getEmail() == null || user.getEmail().isBlank()) {
                log.warn("User has no email address for job creation notification: {}", user.getId());
                return;
            }

            // Send job creation email
            sendJobCreationEmail(user, job);
            log.info("Job creation notification sent to {} for job {}", user.getEmail(), job.getJobNumber());

        } catch (Exception e) {
            log.error("Failed to send job creation notification for job {}: {}", jobId, e.getMessage(), e);
        }
    }

    private void sendJobCreationEmail(User user, Job job) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(smtpUsername);
        message.setTo(user.getEmail());
        message.setSubject(
                "Neuer Job erstellt - " + (job.getJobNumber() != null ? job.getJobNumber() : "Job " + job.getId()));

        String fullName = buildFullName(user);

        // Count tasks for this job
        var allTasks = taskAssignmentService.findTasksForJob(job);
        int taskCount = allTasks.size();

        StringBuilder body = new StringBuilder();
        body.append("Hallo ").append(fullName).append(",\n\n");
        body.append("ein neuer Job wurde erfolgreich erstellt:\n\n");
        body.append("Job: ").append(job.getJobNumber() != null ? job.getJobNumber() : "Unbekannt").append("\n");

        if (job.getCustomerSelection() != null && !job.getCustomerSelection().isBlank()) {
            body.append("Auftraggeber: ").append(job.getCustomerSelection()).append("\n");
        }

        String deliveryCities = job.getDeliveryCitiesDisplay();
        if (job.getPickupCity() != null || deliveryCities != null) {
            body.append("Route: ");
            if (job.getPickupCity() != null) {
                body.append(job.getPickupCity());
            }
            if (job.getPickupCity() != null && deliveryCities != null) {
                body.append(" → ");
            }
            if (deliveryCities != null) {
                body.append(deliveryCities);
            }
            body.append("\n");
        }

        if (taskCount > 0) {
            body.append("Anzahl Aufgaben: ").append(taskCount).append("\n");
        }

        body.append("Status: ").append(job.getStatus() != null ? job.getStatus().getDisplayName() : "Unbekannt")
                .append("\n");

        if (job.getRemark() != null && !job.getRemark().isBlank()) {
            body.append("Bemerkung: ").append(job.getRemark()).append("\n");
        }

        body.append("Erstellt am: ")
                .append(job.getCreatedAt() != null
                        ? job.getCreatedAt().format(java.time.format.DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"))
                        : "Unbekannt")
                .append("\n\n");

        body.append("Der Job ist nun im System verfügbar und kann bearbeitet werden.\n\n");
        body.append("Mit freundlichen Grüßen,\n");
        body.append("Ihr Votianlt-System");

        message.setText(body.toString());
        mailSender.send(message);
    }

    /**
     * Send a text email with a single attachment. Synchronous on purpose so
     * callers can report per-recipient success or failure to the user.
     */
    public void sendEmailWithAttachment(String to, String subject, String body, byte[] attachment,
            String attachmentName) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
        helper.setFrom(smtpUsername);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(body);
        helper.addAttachment(attachmentName, new ByteArrayResource(attachment));
        mailSender.send(message);
        log.info("Email with attachment {} sent to {}", attachmentName, to);
    }

    /**
     * Send a simple text email
     */
    @Async
    public void sendSimpleEmail(String to, String subject, String body) {
        try {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom(smtpUsername);
            message.setTo(to);
            message.setSubject(subject);
            message.setText(body);

            mailSender.send(message);
            log.debug("Simple email sent to {} with subject: {}", to, subject);

        } catch (Exception e) {
            log.error("Failed to send simple email to {} with subject '{}': {}", to, subject, e.getMessage(), e);
        }
    }
}
