package be.seeseepuff.allowanceplanner.service;

import be.seeseepuff.allowanceplanner.dto.MigrationDto;
import be.seeseepuff.allowanceplanner.repository.AllowanceRepository;
import be.seeseepuff.allowanceplanner.repository.HistoryRepository;
import be.seeseepuff.allowanceplanner.repository.TaskRepository;
import be.seeseepuff.allowanceplanner.repository.UserRepository;
import jakarta.persistence.EntityManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MigrationService {
    private final UserRepository userRepository;
    private final AllowanceRepository allowanceRepository;
    private final HistoryRepository historyRepository;
    private final TaskRepository taskRepository;
    private final EntityManager entityManager;

    public MigrationService(UserRepository userRepository,
                            AllowanceRepository allowanceRepository,
                            HistoryRepository historyRepository,
                            TaskRepository taskRepository,
                            EntityManager entityManager) {
        this.userRepository = userRepository;
        this.allowanceRepository = allowanceRepository;
        this.historyRepository = historyRepository;
        this.taskRepository = taskRepository;
        this.entityManager = entityManager;
    }

    @Transactional
    public void importData(MigrationDto data) {
        // Delete in dependency order
        taskRepository.deleteAll();
        historyRepository.deleteAll();
        allowanceRepository.deleteAll();
        userRepository.deleteAll();

        // Insert users with original IDs using native SQL to bypass auto-increment
        for (MigrationDto.MigrationUserDto u : data.users()) {
            entityManager.createNativeQuery(
                            "INSERT INTO users (id, name, balance, weight) VALUES (:id, :name, :balance, :weight)")
                    .setParameter("id", u.id())
                    .setParameter("name", u.name())
                    .setParameter("balance", u.balance())
                    .setParameter("weight", u.weight())
                    .executeUpdate();
        }

        // Insert allowances with original IDs
        for (MigrationDto.MigrationAllowanceDto a : data.allowances()) {
            entityManager.createNativeQuery(
                            "INSERT INTO allowances (id, user_id, name, target, balance, weight, colour) VALUES (:id, :userId, :name, :target, :balance, :weight, :colour)")
                    .setParameter("id", a.id())
                    .setParameter("userId", a.userId())
                    .setParameter("name", a.name())
                    .setParameter("target", a.target())
                    .setParameter("balance", a.balance())
                    .setParameter("weight", a.weight())
                    .setParameter("colour", a.colour())
                    .executeUpdate();
        }

        // Insert history with original IDs
        for (MigrationDto.MigrationHistoryDto h : data.history()) {
            entityManager.createNativeQuery(
                            "INSERT INTO history (id, user_id, timestamp, amount, description) VALUES (:id, :userId, :timestamp, :amount, :description)")
                    .setParameter("id", h.id())
                    .setParameter("userId", h.userId())
                    .setParameter("timestamp", h.timestamp())
                    .setParameter("amount", h.amount())
                    .setParameter("description", h.description())
                    .executeUpdate();
        }

        // Insert tasks with original IDs
        for (MigrationDto.MigrationTaskDto t : data.tasks()) {
            entityManager.createNativeQuery(
                            "INSERT INTO tasks (id, name, reward, assigned, schedule, completed, next_run) VALUES (:id, :name, :reward, :assigned, :schedule, :completed, :nextRun)")
                    .setParameter("id", t.id())
                    .setParameter("name", t.name())
                    .setParameter("reward", t.reward())
                    .setParameter("assigned", t.assigned())
                    .setParameter("schedule", t.schedule())
                    .setParameter("completed", t.completed())
                    .setParameter("nextRun", t.nextRun())
                    .executeUpdate();
        }

        // Reset sequences so new inserts don't collide with migrated IDs
        entityManager.createNativeQuery("SELECT setval('users_id_seq', COALESCE((SELECT MAX(id) FROM users), 0))").getSingleResult();
        entityManager.createNativeQuery("SELECT setval('allowances_id_seq', COALESCE((SELECT MAX(id) FROM allowances), 0))").getSingleResult();
        entityManager.createNativeQuery("SELECT setval('history_id_seq', COALESCE((SELECT MAX(id) FROM history), 0))").getSingleResult();
        entityManager.createNativeQuery("SELECT setval('tasks_id_seq', COALESCE((SELECT MAX(id) FROM tasks), 0))").getSingleResult();
    }
}
