using Test
using PSBoardDataBase
using StaticArrays
using CSV, DataFrames
using SQLite, DBInterface
using JLD2
using Dates

# hack for LanguageServer
true || include("../src/PSBoardDataBase.jl")

@testset "PSBoardDataBase" begin
    @testset "parse master log" begin
        masterlog_metadata::PSBoardDataBase.QaqcMasterLog.QaqcMasterLogMetadata =
            PSBoardDataBase.QaqcMasterLog.parse_master_log("input/log/57_long.log")
        @test masterlog_metadata.shifters == "Otsubo"
        @test masterlog_metadata.timestamp == DateTime(2024, 07, 26, 10, 33, 05)
        @test masterlog_metadata.runid == 57
        @test masterlog_metadata.shiftscript_version == v"1.0.2"
    end

    @testset "parse clk log" begin
        @test PSBoardDataBase.ClockParser.get_skew("input/slavelogs/main/230_51_clk.txt") ==
              14.178571428571429
        @test PSBoardDataBase.ClockParser.get_skew("input/slavelogs/main/448_103_clk.txt") ≈
              12.000000000000000
        @test PSBoardDataBase.ClockParser.get_skew("input/slavelogs/main/209_51_clk.txt") ==
              12.571428571428571

        @test PSBoardDataBase.ClockParser.get_skew_and_riseup(
            "input/slavelogs/main/230_51_clk.txt",
        ) === (14.178571428571429, 14.196428571428571 - 14.107142857142858)
        @test PSBoardDataBase.ClockParser.get_skew_and_riseup(
            "input/slavelogs/main/448_103_clk.txt",
        ) == (12.0, 12.053571428571429 - 11.982142857142858)
        @test PSBoardDataBase.ClockParser.get_skew(
            "input/slavelogs/main/444_103_clk.txt",
        ) == PSBoardDataBase.ClockParser.get_skew_and_riseup(
            "input/slavelogs/main/444_103_clk.txt",
        )[1]

        @test PSBoardDataBase.ClockParser.count_riseup(
            "input/slavelogs/main/230_51_clk.txt",
        ) == 1
        @test PSBoardDataBase.ClockParser.count_riseup(
            "input/slavelogs/main/444_103_clk.txt",
        ) == 22
    end

    @testset "Slave Log parser" begin
        @testset "AsdtpResult" begin
            lines = Iterators.Stateful(
                Iterators.drop(eachline("./input/slavelogs/main/430_100.txt"), 2280),
            )
            result_asdtp = PSBoardDataBase.SlaveLogParser.parse_asdtp_section!(lines)

            @test result_asdtp == PSBoardDataBase.SlaveLogParser.AsdtpResult(
                1,
                0,
                true,
                fill(
                    PSBoardDataBase.SlaveLogParser.AsdtpMeasurement.(fill((0, 1, 0), 32)),
                    8,
                ),
                0,
                1,
                1,
                0,
                0x1,
                0x1,
                0xff,
                0x0,
                0x0,
                0x0,
                MVector((0x1001, 0x2001, 0x3001, 0x4001, 0x5001, 0x6001, 0x7001, 0x8001)),
            )

            lines = Iterators.Stateful(
                Iterators.drop(eachline("./input/slavelogs/main/525_244.txt"), 2280),
            )
            result_asdtp = PSBoardDataBase.SlaveLogParser.parse_asdtp_section!(lines)
            @test result_asdtp.reconfig_done == 0
        end

        @testset "Power" begin
            lines = Iterators.Stateful(
                Iterators.drop(eachline("./input/slavelogs/main/430_100.txt"), 1915),
            )
            result = PSBoardDataBase.SlaveLogParser.parse_power_section!(lines)
            @test result.result_3v3d == 3.43
            @test result.result_3v3a == 2.91
            @test result.result_n3va == -2.97

            lines = Iterators.Stateful(
                Iterators.drop(eachline("./input/slavelogs/main/525_244.txt"), 1915),
            )
            result = PSBoardDataBase.SlaveLogParser.parse_power_section!(lines)
            @test result.result_3v3d == 3.47
            @test result.result_3v3a == 2.91
            @test result.result_n3va == -3.01

            lines = Iterators.Stateful(
                Iterators.drop(eachline("./input/slavelogs/main/127_172.txt"), 17),
            )
            result = PSBoardDataBase.SlaveLogParser.parse_power_section!(lines)
            @test result.result_3v3d == 7.65
            @test result.result_3v3a == 3.80
            @test result.result_n3va == -2.87
            @test result.fpga_temp == -63.21
        end

        @testset "Recov" begin
            lines = Iterators.Stateful(
                Iterators.drop(eachline("./input/slavelogs/main/430_100.txt"), 1912),
            )
            @test PSBoardDataBase.SlaveLogParser.parse_recov_section!(lines)

            lines = Iterators.Stateful(
                Iterators.drop(eachline("./input/slavelogs/main/525_244.txt"), 1912),
            )
            @test PSBoardDataBase.SlaveLogParser.parse_recov_section!(lines)

            # Maybe add more cases
        end

        @testset "Integrated" begin
            result = PSBoardDataBase.SlaveLogParser.parse_slavelog_file(
                "./input/slavelogs/main/430_100.txt",
            )
            @test result isa NamedTuple
            @test result.asdtp |> length |> ==(1)
            @test result.power |> length |> ==(1)
            @test result.power[1].result_3v3d == 3.43
            @test result.recov[1]

            @test PSBoardDataBase.SlaveLogParser.parse_slavelog_file(
                "./input/slavelogs/main/525_244.txt",
            ) isa NamedTuple

            result = PSBoardDataBase.SlaveLogParser.parse_slavelog_file(
                "./input/slavelogs/main/525_245_longrun.txt",
            )
            @test result isa NamedTuple
            # @test result.asdtp |> length |> ==(100)
            @test result.power |> length |> ==(0)
            @info "" result.asdtp |> length result.power |> length
            @test readlines("./input/slavelogs/main/525_245_longrun.txt") |>
                  filter(contains("=== Test Power Start ==")) |>
                  length |>
                  ==(length(result.power))

            result = PSBoardDataBase.SlaveLogParser.parse_slavelog_file(
                "./input/slavelogs/main/364_88_longrun.txt",
            )
            @test result isa NamedTuple
            @test result.asdtp |> length |> ==(100)
            @test result.power |> length |> ==(0)
            @info "" result.asdtp |> length result.power |> length
            @test readlines("./input/slavelogs/main/364_88_longrun.txt") |>
                  filter(contains("=== Test Power Start ==")) |>
                  length |>
                  ==(length(result.power))
        end
    end

    @testset "Download data csv" begin
        out = tempname()
        @test CSV.read(
            PSBoardDataBase.DownloadCSVs.download_single_run_csv(out),
            DataFrame,
        ) isa DataFrame
        @test CSV.read(
            PSBoardDataBase.DownloadCSVs.download_runlist_csv(out),
            DataFrame,
        ) isa DataFrame
        @test CSV.read(
            PSBoardDataBase.DownloadCSVs.download_dispatch_csv(out),
            DataFrame,
        ) isa DataFrame
        @test CSV.read(
            PSBoardDataBase.DownloadCSVs.download_hundred_run_csv(out),
            DataFrame,
        ) isa DataFrame
        @test CSV.read(PSBoardDataBase.DownloadCSVs.download_jathub_csv(out), DataFrame) isa
              DataFrame
    end

    @testset "prepare dataframe" begin
        single_result_df =
            CSV.read(PSBoardDataBase.DownloadCSVs.download_single_run_csv(), DataFrame)
        @test PSBoardDataBase.prepare_single_result_df(single_result_df) isa DataFrame

        @test PSBoardDataBase.prepare_dispatch_table(
            CSV.read(PSBoardDataBase.DownloadCSVs.download_dispatch_csv(), DataFrame),
        ) isa DataFrame

        @test PSBoardDataBase.prepare_100test_table(
            CSV.read(PSBoardDataBase.DownloadCSVs.download_hundred_run_csv(), DataFrame),
        ) isa DataFrame
    end

    @testset "full integrated test" begin
        dbpath = tempname()
        jld2path = tempname()
        db = PSBoardDataBase.create_empty_database(dbpath)
        jld2_slavelog = jldopen(jld2path, "w")
        @info "" db jld2_slavelog

        @test PSBoardDataBase.insert_version_info(db, jld2_slavelog) |> isnothing
        let stmt
            stmt = DBInterface.prepare(
                db,
                sql"""
                SELECT * FROM versions
                """,
            )
            result = DBInterface.execute(stmt) |> DataFrame
            @test nrow(result) |> ==(1)
        end

        @test PSBoardDataBase.insert_qaqc_campaign_id(db) |> isnothing
        jathub_list_df =
            CSV.read(PSBoardDataBase.DownloadCSVs.download_jathub_csv(), DataFrame)
        @test PSBoardDataBase.insert_qaqc_positions(db, jathub_list_df) |> isnothing

        single_result_df =
            CSV.read(PSBoardDataBase.DownloadCSVs.download_single_run_csv(), DataFrame)
        runlist_table =
            CSV.read(PSBoardDataBase.DownloadCSVs.download_runlist_csv(), DataFrame)

        @test PSBoardDataBase.add_psboard_ids(db, single_result_df) |> isnothing
        @test PSBoardDataBase.add_qaqc_runlist_from_runlist(db, runlist_table) |> isnothing

        @test PSBoardDataBase.add_qaqc_single_result(db, single_result_df, runlist_table) |>
              isnothing

        dispatch_table =
            CSV.read(PSBoardDataBase.DownloadCSVs.download_dispatch_csv(), DataFrame)

        @test PSBoardDataBase.add_qaqc_dispatch(db, dispatch_table) |> isnothing

        if haskey(ENV, "LOCAL_TEST")
            @test PSBoardDataBase.add_qaqc_runlist_from_masterlogs(db, "input/log/") |>
                  isnothing

            extra_100test_result_df =
                CSV.read(PSBoardDataBase.DownloadCSVs.download_hundred_run_csv(), DataFrame)

            @test PSBoardDataBase.add_qaqc_100test_result(
                db,
                extra_100test_result_df,
                "input/slavelogs/",
                jld2_slavelog,
            ) |> isnothing

            @test PSBoardDataBase.add_skew_from_slave_clk_logs(db, "input/slavelogs/") |>
                  isnothing

            @test PSBoardDataBase.add_slavelog_result(
                db,
                "input/slavelogs/",
                jld2_slavelog,
            ) |> isnothing

            run(`sqlitebrowser $dbpath`)

            @test PSBoardDataBase.create_database(
                tempname();
                masterlog_dir = "input/log/",
                slavelog_dir = "input/slavelogs/",
                slavelog_result = tempname(),
            ) isa SQLite.DB
        end

        @testset "DbConnection" begin
            conn = PSBoardDataBase.DispatchChecker.DbConnection(db)

            @test conn.df_single_result isa DataFrame
            @info "" conn.df_single_result |> nrow conn.df_extra_results |> nrow

            if haskey(ENV, "LOCAL_TEST")
                @test PSBoardDataBase.DispatchChecker.is_dispatchable(conn, 443)
                @test PSBoardDataBase.DispatchChecker.is_dispatchable(conn, 706) |>
                      ismissing
            end
        end
    end
end

using Aqua

@testset "Aqua.jl" begin
    Aqua.test_all(
        PSBoardDataBase;
        # ambiguities = (exclude = [], broken = true),
        stale_deps = (ignore = Symbol[:Documenter],),
        # deps_compat = (ignore = Symbol[],),
        # piracies = false,
    )
end
