vim.env.PLENARY_TEST_TIMEOUT = 60000
local runner = require('neotest-haskell.runner')
local async = require('nio').tests

local simple_cabal_hspec_test_file = 'spec/fixtures/hspec/cabal/simple/test/FirstSpec.hs'
local multi_package_cabal_hspec_test_file =
  'spec/fixtures/hspec/cabal/multi-package/subpackage1/test/Fix1/FixtureSpec.hs'
local simple_stack_hspec_test_file = 'spec/fixtures/hspec/stack/simple/test/FirstSpec.hs'
local simple_stack_hspec_test_file_only_package_yaml = 'spec/fixtures/hspec/stack/simple-package-yaml/test/FirstSpec.hs'
local multi_package_stack_hspec_test_file =
  'spec/fixtures/hspec/stack/multi-package/subpackage1/test/Fix1/FixtureSpec.hs'
local multi_package_cabal_tasty_test_file = 'spec/fixtures/tasty/cabal/multi-package/tasty-pkg/test/Spec.hs'
local simple_cabal_sydtest_test_file = 'spec/fixtures/sydtest/cabal/simple/test/SydtestFixtureSpec.hs'

local hspec = require('neotest-haskell.hspec')
local tasty = require('neotest-haskell.tasty')
local sydtest = require('neotest-haskell.sydtest')

describe('runner', function()
  describe('select_framework', function()
    async.it('selects hspec for hspec file', function()
      assert.same(hspec, runner.select_framework(multi_package_cabal_hspec_test_file, { 'sydtest', 'tasty', 'hspec' }))
    end)
    async.it('selects tasty for tasty file if tasty is specified before hspec', function()
      assert.same(tasty, runner.select_framework(multi_package_cabal_tasty_test_file, { 'sydtest', 'tasty', 'hspec' }))
    end)
    async.it('selects sydtest for sydtest file if sydtest is specified before hspec', function()
      assert.same(sydtest, runner.select_framework(simple_cabal_sydtest_test_file, { 'sydtest', 'tasty', 'hspec' }))
    end)
    async.it('errors for hspec file if hspec is not specified', function()
      assert.has_error(function()
        runner.select_framework(multi_package_cabal_hspec_test_file, { 'tasty' })
      end)
    end)
    async.it('can detect framework by qualified module name', function()
      assert.same(
        hspec,
        runner.select_framework(
          multi_package_cabal_hspec_test_file,
          { { framework = 'hspec', modules = { 'Fix1.FixtureSpec' } } }
        )
      )
    end)
  end)

  describe('select_build_tool', function()
    describe('simple project without stack.yaml', function()
      it('uses cabal if it is in the list of build tools', function()
        local mk_command = runner.select_build_tool(hspec, simple_cabal_hspec_test_file, { 'stack', 'cabal' })
        local command = mk_command()
        assert.same(command[1], 'cabal')
      end)
      it('throws if only stack is specified', function()
        assert.has_error(function()
          runner.select_build_tool(hspec, simple_cabal_hspec_test_file, { 'stack' })
        end)
      end)
      it('throws if no build tool is specified', function()
        assert.has_error(function()
          runner.select_build_tool(hspec, simple_cabal_hspec_test_file, {})
        end)
      end)
    end)

    describe('multi-package project without stack.yaml', function()
      it('uses cabal if it is in the list of build tools', function()
        local mk_command = runner.select_build_tool(hspec, multi_package_cabal_hspec_test_file, { 'stack', 'cabal' })
        local command = mk_command()
        assert.same(command[1], 'cabal')
        assert.same(command[3], 'subpackage1')
      end)
      it('throws if only stack is specified', function()
        assert.has_error(function()
          runner.select_build_tool(hspec, multi_package_cabal_hspec_test_file, { 'stack' })
        end)
      end)
      it('throws if no build tool is specified', function()
        assert.has_error(function()
          runner.select_build_tool(hspec, multi_package_cabal_hspec_test_file, {})
        end)
      end)
    end)

    describe('simple project with stack.yaml', function()
      it('uses stack if it is in the list of build tools before cabal', function()
        local mk_command = runner.select_build_tool(hspec, simple_stack_hspec_test_file, { 'stack', 'cabal' })
        local command = mk_command()
        assert.same(command[1], 'stack')
      end)
      it('uses stack if it is the only build tool', function()
        local mk_command = runner.select_build_tool(hspec, simple_stack_hspec_test_file, { 'stack' })
        local command = mk_command()
        assert.same(command[1], 'stack')
      end)
    end)
    it('throws if no build tool is specified', function()
      assert.has_error(function()
        runner.select_build_tool(hspec, '.', {})
      end)
    end)

    describe('simple project with stack.yaml, package.yaml and no *.cabal', function()
      it('uses stack if it is in the list of build tools before cabal', function()
        local mk_command =
          runner.select_build_tool(hspec, simple_stack_hspec_test_file_only_package_yaml, { 'stack', 'cabal' })
        local command = mk_command()
        assert.same(command[1], 'stack')
      end)
      it('uses stack if it is the only build tool', function()
        local mk_command = runner.select_build_tool(hspec, simple_stack_hspec_test_file_only_package_yaml, { 'stack' })
        local command = mk_command()
        assert.same(command[1], 'stack')
      end)
    end)
    it('throws if no build tool is specified', function()
      assert.has_error(function()
        runner.select_build_tool(hspec, '.', {})
      end)
    end)

    describe('multi-package project with stack.yaml', function()
      it('uses stack if it is in the list of build tools before cabal', function()
        local mk_command = runner.select_build_tool(hspec, multi_package_stack_hspec_test_file, { 'stack', 'cabal' })
        local command = mk_command()
        assert.same(command[1], 'stack')
        assert.same(command[3], 'subpackage1')
      end)
      it('uses stack if it is the only build tool', function()
        local mk_command = runner.select_build_tool(hspec, multi_package_stack_hspec_test_file, { 'stack' })
        local command = mk_command()
        assert.same(command[1], 'stack')
      end)
    end)
    it('throws if no build tool is specified', function()
      assert.has_error(function()
        runner.select_build_tool(hspec, '.', {})
      end)
    end)
  end)
end)
