package com.iqser.red.service.persistence.management.v1.processor.migration;

import java.util.Comparator;
import java.util.List;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import com.iqser.red.service.persistence.management.v1.processor.service.persistence.MigrationPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.settings.FileManagementServiceSettings;
import com.iqser.red.service.persistence.management.v1.processor.utils.TenantUtils;
import com.knecon.fforesight.tenantcommons.TenantContext;
import com.knecon.fforesight.tenantcommons.TenantProvider;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class MigrationStarterService {

    private final List<Migration> migrations;
    private final FileManagementServiceSettings settings;
    private final ApplicationContext ctx;
    private final MigrationPersistenceService migrationPersistenceService;
    private final TenantProvider tenantProvider;


    @EventListener(ApplicationReadyEvent.class)
    public void migrate() {

        tenantProvider.getTenants().forEach(tenant -> {

            if (!TenantUtils.isTenantReadyForPersistence(tenant)) {
                return;
            }

            TenantContext.setTenantId(tenant.getTenantId());

            //This is always running on startup
            seedMigration();
        });

        // This should only run in post upgrade hook
        if (settings.isMigrateOnly()) {

            tenantProvider.getTenants().forEach(tenant -> {

                if (!TenantUtils.isTenantReadyForPersistence(tenant)) {
                    return;
                }

                runForTenant(tenant.getTenantId());
            });

            log.info("Migration is finished");
            System.exit(SpringApplication.exit(ctx, () -> 0));

        }
    }


    private void seedMigration() {

        if (migrationPersistenceService.getLatestProcessedVersion() == null) {
            migrations.sort(Comparator.comparing(Migration::getVersion).reversed());
            migrationPersistenceService.insertMigration("migration start version", migrations.get(0).getVersion());
        }
    }


    public synchronized void runForTenant(String tenantId) {

        TenantContext.setTenantId(tenantId);

        seedMigration(); // Needed if tenant is created that is not migrated.
        log.info("Start migration for tentant: " + tenantId);

        migrations.sort(Comparator.comparing(Migration::getVersion));

        for (var migration : migrations) {
            migration.run();
        }

        log.info("Migration is finished for tenant: " + tenantId);
    }

}
