package cmd

import (
	"context"
	"os"
	"path"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var v2ConfigExample string = `
quiet: False
disable-version-string: True
with-expecter: True
mockname: "{{.InterfaceName}}"
filename: "{{.StructName}}_mock.go"
outpkg: mocks
tags: "custom2"
issue-845-fix: True
resolve-type-alias: False
_anchors: &inpackage_config
  all: True
  dir: "{{.InterfaceDir}}"
  mockname: "Mock{{.InterfaceName}}"
  outpkg: "{{.PackageName}}_test"
  filename: "mock_{{.InterfaceNameSnake}}_test.go"
  inpackage: False
packages:
  github.com/vektra/mockery/v2/pkg/fixtures/buildtag/comment:
    config:
      mock-build-tags: "custom3 && (!windows || !darwin || !freebsd)"
      disable-version-string: true
    interfaces:
      IfaceWithCustomBuildTagInComment:
  github.com/vektra/mockery/v2/pkg:
    interfaces:
      TypesPackage:
  github.com/vektra/mockery/v2/pkg/fixtures:
    config:
      all: True
    interfaces:
      RequesterArgSameAsNamedImport:
      RequesterVariadic:
        config:
          with-expecter: False
        configs:
          - mockname: RequesterVariadicOneArgument
            unroll-variadic: False
          - mockname: RequesterVariadic
            unroll-variadic: True
      Expecter:
        config:
          with-expecter: True
        configs:
          - mockname: ExpecterAndRolledVariadic
            unroll-variadic: False
          - mockname: Expecter
            unroll-variadic: True
      RequesterReturnElided:
      VariadicNoReturnInterface:
        config:
          with-expecter: True
          unroll-variadic: False
      # Replace generic params with a new constraint and a new fixed value
      ReplaceGeneric:
        config:
          replace-type:
            - github.com/vektra/mockery/v2/pkg/fixtures.ReplaceGeneric[-TImport]=github.com/vektra/mockery/v2/pkg/fixtures/redefined_type_b.B
            - github.com/vektra/mockery/v2/pkg/fixtures.ReplaceGeneric[TConstraint]=github.com/vektra/mockery/v2/pkg/fixtures/constraints.String
      # Replace a generic param with the parent type
      ReplaceGenericSelf:
        config:
          replace-type:
            - github.com/vektra/mockery/v2/pkg/fixtures.ReplaceGenericSelf[-T]=github.com/vektra/mockery/v2/pkg/fixtures.*ReplaceGenericSelf
  github.com/vektra/mockery/v2/pkg/fixtures/recursive_generation:
    config:
      recursive: True
      all: True
      dir: "{{.InterfaceDir}}"
      filename: "{{.InterfaceName}}_mock.go"
      mockname: "Mock{{.InterfaceName}}"
      outpkg: "{{.PackageName}}"
      inpackage: True
  github.com/vektra/mockery/v2/pkg/fixtures/empty_return:
    config:
      all: True
      dir: "{{.InterfaceDir}}"
      mockname: "{{.InterfaceName}}Mock"
      outpkg: "{{.PackageName}}"
      filename: "mock_{{.InterfaceName}}_test.go"
      inpackage: True
      keeptree: False
  github.com/vektra/mockery/v2/pkg/fixtures/method_args/same_name_arg_and_type:
    config:
      all: True
      dir: "{{.InterfaceDir}}"
      mockname: "{{.InterfaceName}}Mock"
      outpkg: "{{.PackageName}}"
      filename: "mock_{{.InterfaceName}}_test.go"
      inpackage: True
      keeptree: False
  github.com/vektra/mockery/v2/pkg/fixtures/iface_typed_param:
    config: *inpackage_config
  github.com/vektra/mockery/v2/pkg/fixtures/example_project:
    config: *inpackage_config
  github.com/vektra/mockery/v2/pkg/fixtures/index_list_expr:
    config: *inpackage_config
  github.com/vektra/mockery/v2/pkg/fixtures/iface_new_type:
    config: *inpackage_config
  github.com/vektra/mockery/v2/pkg/fixtures/issue845:
    config:
      <<: *inpackage_config
      filename: "mock_{{.StructName}}_test.go"
    interfaces:
      Interface:
        configs:
          - issue-845-fix: False
            mockname: WithoutFix
          - issue-845-fix: True
            mockname: WithFix
  github.com/vektra/mockery/v2/pkg/fixtures/type_alias:
    config:
      all: True
      dir: "{{.InterfaceDir}}"
      filename: "mock_{{.StructName}}_test.go"
      outpkg: "{{.PackageName}}_test"
      inpackage: False
    interfaces:
      Interface1:
        configs:
          - resolve-type-alias: False
            mockname: InterfaceWithUnresolvedAlias
          - resolve-type-alias: True
            mockname: InterfaceWithResolvedAlias
      Interface2:
        configs:
          - resolve-type-alias: False
            mockname: Interface2WithUnresolvedAlias
          - resolve-type-alias: True
            mockname: Interface2WithResolvedAlias
  github.com/vektra/mockery/v2/pkg/:
    interfaces:
      InterfaceDoesntExist:
  github.com/vektra/mockery/v2/pkg/fixtures/auto_generated:
    config:
      all: True
      include-auto-generated: false
    interfaces:
      AutoGenerated: # include-auto-generated is false, so should be ignored
`

var expectedV3Conf string = `_anchors:
  all: true
  dir: '{{.InterfaceDir}}'
  filename: mock_{{.InterfaceNameSnake}}_test.go
  inpackage: false
  mockname: Mock{{.InterfaceName}}
  outpkg: '{{.PackageName}}_test'
structname: '{{.InterfaceName}}'
pkgname: mocks
template: testify
template-data:
  unroll-variadic: true
packages:
  github.com/vektra/mockery/v2/pkg:
    interfaces:
      TypesPackage: {}
  github.com/vektra/mockery/v2/pkg/:
    interfaces:
      InterfaceDoesntExist: {}
  github.com/vektra/mockery/v2/pkg/fixtures:
    config:
      all: true
    interfaces:
      Expecter:
        config: {}
        configs:
          - structname: ExpecterAndRolledVariadic
            template-data:
              unroll-variadic: false
          - structname: Expecter
            template-data:
              unroll-variadic: true
      ReplaceGeneric:
        config: {}
      ReplaceGenericSelf:
        config: {}
      RequesterArgSameAsNamedImport: {}
      RequesterReturnElided: {}
      RequesterVariadic:
        config: {}
        configs:
          - structname: RequesterVariadicOneArgument
            template-data:
              unroll-variadic: false
          - structname: RequesterVariadic
            template-data:
              unroll-variadic: true
      VariadicNoReturnInterface:
        config:
          template-data:
            unroll-variadic: false
  github.com/vektra/mockery/v2/pkg/fixtures/auto_generated:
    config:
      all: true
      include-auto-generated: false
    interfaces:
      AutoGenerated: {}
  github.com/vektra/mockery/v2/pkg/fixtures/buildtag/comment:
    config:
      template-data:
        mock-build-tags: custom3 && (!windows || !darwin || !freebsd)
    interfaces:
      IfaceWithCustomBuildTagInComment: {}
  github.com/vektra/mockery/v2/pkg/fixtures/empty_return:
    config:
      all: true
      dir: '{{.InterfaceDir}}'
      structname: '{{.InterfaceName}}Mock'
      pkgname: '{{.PackageName}}'
  github.com/vektra/mockery/v2/pkg/fixtures/example_project:
    config:
      all: true
      dir: '{{.InterfaceDir}}'
      structname: Mock{{.InterfaceName}}
      pkgname: '{{.PackageName}}_test'
  github.com/vektra/mockery/v2/pkg/fixtures/iface_new_type:
    config:
      all: true
      dir: '{{.InterfaceDir}}'
      structname: Mock{{.InterfaceName}}
      pkgname: '{{.PackageName}}_test'
  github.com/vektra/mockery/v2/pkg/fixtures/iface_typed_param:
    config:
      all: true
      dir: '{{.InterfaceDir}}'
      structname: Mock{{.InterfaceName}}
      pkgname: '{{.PackageName}}_test'
  github.com/vektra/mockery/v2/pkg/fixtures/index_list_expr:
    config:
      all: true
      dir: '{{.InterfaceDir}}'
      structname: Mock{{.InterfaceName}}
      pkgname: '{{.PackageName}}_test'
  github.com/vektra/mockery/v2/pkg/fixtures/issue845:
    config:
      all: true
      dir: '{{.InterfaceDir}}'
      structname: Mock{{.InterfaceName}}
      pkgname: '{{.PackageName}}_test'
    interfaces:
      Interface:
        configs:
          - structname: WithoutFix
          - structname: WithFix
  github.com/vektra/mockery/v2/pkg/fixtures/method_args/same_name_arg_and_type:
    config:
      all: true
      dir: '{{.InterfaceDir}}'
      structname: '{{.InterfaceName}}Mock'
      pkgname: '{{.PackageName}}'
  github.com/vektra/mockery/v2/pkg/fixtures/recursive_generation:
    config:
      all: true
      dir: '{{.InterfaceDir}}'
      structname: Mock{{.InterfaceName}}
      pkgname: '{{.PackageName}}'
      recursive: true
  github.com/vektra/mockery/v2/pkg/fixtures/type_alias:
    config:
      all: true
      dir: '{{.InterfaceDir}}'
      pkgname: '{{.PackageName}}_test'
    interfaces:
      Interface1:
        configs:
          - structname: InterfaceWithUnresolvedAlias
          - structname: InterfaceWithResolvedAlias
      Interface2:
        configs:
          - structname: Interface2WithUnresolvedAlias
          - structname: Interface2WithResolvedAlias
`

func TestMigrate(t *testing.T) {
	tmpdir := t.TempDir()
	v2File := path.Join(tmpdir, "v2_config.yml")
	v3File := path.Join(tmpdir, "v3_config.yml")

	require.NoError(t, os.WriteFile(v2File, []byte(v2ConfigExample), 0o600))
	require.NoError(t, run(context.Background(), v2File, v3File))

	b, err := os.ReadFile(v3File)
	require.NoError(t, err)
	assert.Equal(t, expectedV3Conf, string(b))
}
