package com.lanyuanxiaoyao.digtal.market

import com.lanyuanxiaoyao.digtal.market.runner.NewsRunner
import com.lanyuanxiaoyao.digtal.market.runner.PushRunner
import com.lanyuanxiaoyao.squirrel.core.common.Management
import com.lanyuanxiaoyao.squirrel.core.jvm.BINARY_PATH
import com.lanyuanxiaoyao.squirrel.core.jvm.DRIVER_PATH
import com.lanyuanxiaoyao.squirrel.core.jvm.JvmManagement
import com.lanyuanxiaoyao.squirrel.core.jvm.LocalFileDatabase
import jakarta.annotation.Resource
import org.slf4j.LoggerFactory
import org.springframework.boot.ApplicationArguments
import org.springframework.boot.ApplicationRunner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.boot.context.properties.bind.ConstructorBinding
import org.springframework.boot.runApplication
import org.springframework.context.ApplicationListener
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.event.ContextClosedEvent
import org.springframework.scheduling.annotation.EnableScheduling
import org.springframework.web.servlet.config.annotation.CorsRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer

@ConfigurationProperties(prefix = "messenger.database")
data class DatabaseProperties @ConstructorBinding constructor(
    val h2Path: String,
    val jsonPath: String,
)

@ConfigurationProperties(prefix = "messenger.driver")
data class DriverProperties @ConstructorBinding constructor(
    val driverPath: String,
    val binaryPath: String,
)

@ConfigurationProperties(prefix = "messenger.mail")
data class MailProperties @ConstructorBinding constructor(
    val targets: List<String>,
)

@EnableScheduling
@ConfigurationPropertiesScan
@SpringBootApplication
class Application : ApplicationRunner, ApplicationListener<ContextClosedEvent> {
    private val logger = LoggerFactory.getLogger(javaClass)

    @Resource
    private lateinit var management: Management

    @Resource
    private lateinit var newsRunner: NewsRunner

    @Resource
    private lateinit var pushRunner: PushRunner

    override fun run(args: ApplicationArguments?) {
        // pushRunner.run()
        // newsRunner.run()
    }

    override fun onApplicationEvent(event: ContextClosedEvent) {
        management.exit()
    }
}

@Configuration
class Configuration {
    private val logger = LoggerFactory.getLogger(javaClass)

    @Bean
    fun jvmManagement(
        driverProperties: DriverProperties,
        databaseProperties: DatabaseProperties,
    ): Management = JvmManagement(
        database = LocalFileDatabase(databaseProperties.jsonPath)
    ).also { management ->
        logger.info("Loaded driver path: {}", driverProperties.driverPath)
        logger.info("Loaded binary path: {}", driverProperties.binaryPath)
        logger.info("Loaded database path: {}", databaseProperties.h2Path)
        logger.info("Loaded database path: {}", databaseProperties.jsonPath)
        management
            .fetchConfiguration()
            .let { information ->
                if (information.httpDownloaderName.isBlank()) {
                    management.changeDownloader("basicCacheDownloader")
                }
                if (information.browserDownloaderName.isBlank()) {
                    management.changeDownloader(
                        "chromeCacheDownloader",
                        mapOf(
                            BINARY_PATH to driverProperties.binaryPath,
                            DRIVER_PATH to driverProperties.driverPath,
                        )
                    )
                }
            }
        management.importSites(sites)
    }
}

@Configuration
class WebConfiguration : WebMvcConfigurer {
    override fun addCorsMappings(registry: CorsRegistry) {
        registry
            .addMapping("/**")
            .allowedOriginPatterns("*")
            .allowCredentials(true)
            .allowedMethods("*")
            .maxAge(3600)
    }
}

fun main(args: Array<String>) {
    runApplication<Application>(*args)
}
