package de.votian.services.service;

import de.votian.services.config.LegacySchedulingProperties;
import de.votian.services.config.ParameterKeys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

@Service
public class LegacyCourierAutoLogoutService {

    private static final Logger log = LoggerFactory.getLogger(LegacyCourierAutoLogoutService.class);

    private final JdbcTemplate jdbcTemplate;
    private final ParameterService parameterService;
    private final LegacySchedulingProperties schedulingProperties;
    private final AtomicBoolean running = new AtomicBoolean();

    public LegacyCourierAutoLogoutService(JdbcTemplate jdbcTemplate,
                                          ParameterService parameterService,
                                          LegacySchedulingProperties schedulingProperties) {
        this.jdbcTemplate = jdbcTemplate;
        this.parameterService = parameterService;
        this.schedulingProperties = schedulingProperties;
    }

    @Transactional
    public int logoutCouriersByAutorevokes() {
        if (!running.compareAndSet(false, true)) {
            log.info("Legacy courier auto logout is still running, skipping overlapping execution.");
            return 0;
        }

        try {
            List<CourierLogState> candidates = loadCandidates(schedulingProperties.getCourierAutoLogoutHeadquartersId());
            int loggedOut = 0;
            for (CourierLogState candidate : candidates) {
                if (candidate.acceptedCount() > 0 || candidate.cancelledCount() > 0 || candidate.revokedCount() < 2) {
                    continue;
                }
                if (isOccupied(candidate.courierId())) {
                    continue;
                }
                logoutCourier(candidate);
                loggedOut++;
            }
            if (loggedOut > 0) {
                log.info("Legacy courier auto logout logged out {} courier(s).", loggedOut);
            }
            return loggedOut;
        } finally {
            running.set(false);
        }
    }

    private List<CourierLogState> loadCandidates(long headquartersId) {
        return jdbcTemplate.query(
                """
                        SELECT cr.cr_id,
                               cr.cr_eid,
                               cr.hq_id,
                               SUM(CASE WHEN log.logo_id = 3 THEN 1 ELSE 0 END) AS accepted_count,
                               SUM(CASE WHEN log.logo_id = 8 THEN 1 ELSE 0 END) AS revoked_count,
                               SUM(CASE WHEN log.logo_id = 11 THEN 1 ELSE 0 END) AS cancelled_count
                        FROM courier AS cr
                        JOIN phoenix_log.log AS log ON log.cr_id = cr.cr_id
                        WHERE cr.cr_available = '1'
                          AND cr.hq_id = ?
                          AND cr.cr_locationzipcode REGEXP '^[0-9]+$'
                          AND log.log_createtime >= DATE_SUB(NOW(), INTERVAL 30 MINUTE)
                          AND log.logo_id IN (3, 8, 11)
                        GROUP BY cr.cr_id, cr.cr_eid, cr.hq_id
                        ORDER BY cr.cr_id
                        """,
                (rs, rowNum) -> new CourierLogState(
                        rs.getLong("cr_id"),
                        rs.getString("cr_eid"),
                        rs.getLong("hq_id"),
                        rs.getInt("accepted_count"),
                        rs.getInt("revoked_count"),
                        rs.getInt("cancelled_count")
                ),
                headquartersId
        );
    }

    private boolean isOccupied(long courierId) {
        Integer matches = jdbcTemplate.queryForObject(
                """
                        SELECT COUNT(*)
                        FROM courier AS cr
                        JOIN job AS jb ON jb.cr_id_order = cr.cr_id
                        JOIN tour AS tr ON tr.jb_id = jb.jb_id AND tr.tr_sort = 1
                        JOIN address AS ad ON tr.ad_id = ad.ad_id
                        LEFT JOIN serviceplz AS srvp ON ad.ad_zipcode = srvp.srvp_plz
                        LEFT JOIN serviceplztraveltime AS srvpt ON srvp.srvp_id = srvpt.srvp_id
                        WHERE cr.cr_id = ?
                          AND jb.jb_status IN (0, 1)
                          AND DATE_SUB(jb.jb_ordertime, INTERVAL GREATEST(COALESCE(srvpt.srvpt_traveltime, 0), 30) MINUTE) <= NOW()
                          AND (srvpt.hq_id = jb.hq_id OR srvpt.hq_id IS NULL)
                        """,
                Integer.class,
                courierId
        );
        return matches != null && matches > 0;
    }

    private void logoutCourier(CourierLogState candidate) {
        LocalDateTime now = LocalDateTime.now().withNano(0);
        LocalDateTime executeUntil = now.plusMinutes(16);

        jdbcTemplate.update(
                "UPDATE courier SET cr_availabletime = ?, cr_locationzipcode = ? WHERE cr_id = ?",
                Timestamp.valueOf(now),
                "LOGOUT",
                candidate.courierId()
        );
        jdbcTemplate.update(
                """
                        INSERT INTO phoenix_pda.commandexec
                            (cr_id, hq_id, cmd_command, cmde_exec_time, cmde_exec_timelimit, cmde_mode, cmde_param)
                        VALUES (?, ?, ?, ?, ?, ?, ?)
                        """,
                candidate.courierId(),
                candidate.headquartersId(),
                "2",
                Timestamp.valueOf(now),
                Timestamp.valueOf(executeUntil),
                "1",
                ""
        );

        if ("1".equals(parameterService.getParameterValueWithFallback(ParameterKeys.LOG_DB, candidate.headquartersId()))) {
            jdbcTemplate.update(
                    """
                            INSERT INTO phoenix_log.log
                                (logo_id, hq_id, jb_id, usr_id, cr_id, cr_sid, cs_id, at_id, pt_id, emp_id, logo_description)
                            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                            """,
                    143,
                    candidate.headquartersId(),
                    0,
                    0,
                    candidate.courierId(),
                    "",
                    0,
                    0,
                    0,
                    0,
                    "STATUS_LOGOUT=PDA-LOGOUT DURCH AUTOREVOKES"
            );
        }

        log.info("Legacy courier auto logout logged out courier {} ({})", candidate.courierId(), candidate.courierEid());
    }

    private record CourierLogState(long courierId,
                                   String courierEid,
                                   long headquartersId,
                                   int acceptedCount,
                                   int revokedCount,
                                   int cancelledCount) {
    }
}
