// Copyright 2019 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// bpdoc docs.
package bpdoc

import (
	"html/template"
	"reflect"
	"runtime"
	"testing"

	"github.com/google/blueprint"
)

type factoryFn func() (blueprint.Module, []interface{})

// foo docs.
func fooFactory() (blueprint.Module, []interface{}) {
	return nil, []interface{}{&props{}}
}

// bar docs.
func barFactory() (blueprint.Module, []interface{}) {
	return nil, []interface{}{&complexProps{}}
}

type structToNest struct {
	E string
}

type StructToEmbed struct {
	Nested_in_embedded structToNest

	// F string
	F string
}

type otherStructToNest struct {
	G string
}

type OtherStructToEmbed struct {
	Nested_in_other_embedded otherStructToNest

	// F string
	H string
}

type StructWithEmbedded struct {
	StructToEmbed
}

// for bpdoc_test.go
type complexProps struct {
	A         string
	B_mutated string `blueprint:"mutated"`

	Nested struct {
		C         string
		D_mutated string `blueprint:"mutated"`
	}

	Nested_struct structToNest

	Struct_has_embed StructWithEmbedded

	OtherStructToEmbed

	List_of_ints []int

	List_of_nested []structToNest
}

// props docs.
type props struct {
	// A docs.
	A string
}

// for properties_test.go
type tagTestProps struct {
	A string `tag1:"a,b" tag2:"c"`
	B string `tag1:"a,c"`
	C string `tag1:"b,c"`

	D struct {
		E string `tag1:"a,b" tag2:"c"`
		F string `tag1:"a,c"`
		G string `tag1:"b,c"`
	} `tag1:"b,c"`
}

var pkgPath string
var pkgFiles map[string][]string
var moduleTypeNameFactories map[string]reflect.Value
var moduleTypeNamePropertyStructs map[string][]interface{}

func init() {
	pc, filename, _, _ := runtime.Caller(0)
	fn := runtime.FuncForPC(pc)

	var err error
	pkgPath, err = funcNameToPkgPath(fn.Name())
	if err != nil {
		panic(err)
	}

	pkgFiles = map[string][]string{
		pkgPath: {filename},
	}

	factories := map[string]factoryFn{"foo": fooFactory, "bar": barFactory}

	moduleTypeNameFactories = make(map[string]reflect.Value, len(factories))
	moduleTypeNamePropertyStructs = make(map[string][]interface{}, len(factories))
	for name, factory := range factories {
		moduleTypeNameFactories[name] = reflect.ValueOf(factory)
		_, structs := factory()
		moduleTypeNamePropertyStructs[name] = structs
	}
}

func TestModuleTypeDocs(t *testing.T) {
	r := NewReader(pkgFiles)
	for m := range moduleTypeNameFactories {
		mt, err := r.ModuleType(m+"_module", moduleTypeNameFactories[m])
		if err != nil {
			t.Fatal(err)
		}

		expectedText := template.HTML(m + " docs.\n\n")
		if mt.Text != expectedText {
			t.Errorf("unexpected docs %q", mt.Text)
		}

		if mt.PkgPath != pkgPath {
			t.Errorf("expected pkgpath %q, got %q", pkgPath, mt.PkgPath)
		}
	}
}

func TestPropertyStruct(t *testing.T) {
	r := NewReader(pkgFiles)
	ps, err := r.PropertyStruct(pkgPath, "props", reflect.ValueOf(props{A: "B"}))
	if err != nil {
		t.Fatal(err)
	}

	if ps.Text != "props docs.\n" {
		t.Errorf("unexpected docs %q", ps.Text)
	}
	if len(ps.Properties) != 1 {
		t.Fatalf("want 1 property, got %d", len(ps.Properties))
	}

	if ps.Properties[0].Name != "a" || ps.Properties[0].Text != "A docs.\n\n" || ps.Properties[0].Default != "B" {
		t.Errorf("unexpected property docs %q %q %q",
			ps.Properties[0].Name, ps.Properties[0].Text, ps.Properties[0].Default)
	}
}

func TestPackage(t *testing.T) {
	r := NewReader(pkgFiles)
	pkg, err := r.Package(pkgPath)
	if err != nil {
		t.Fatal(err)
	}

	if pkg.Text != "bpdoc docs.\n" {
		t.Errorf("unexpected docs %q", pkg.Text)
	}
}

func TestFuncToPkgPath(t *testing.T) {
	tests := []struct {
		f    string
		want string
	}{
		{
			f:    "github.com/google/blueprint/bootstrap.Main",
			want: "github.com/google/blueprint/bootstrap",
		},
		{
			f:    "android/soong/android.GenruleFactory",
			want: "android/soong/android",
		},
		{
			f:    "android/soong/android.ModuleFactoryAdapter.func1",
			want: "android/soong/android",
		},
		{
			f:    "main.Main",
			want: "main",
		},
	}
	for _, tt := range tests {
		t.Run(tt.f, func(t *testing.T) {
			got, err := funcNameToPkgPath(tt.f)
			if err != nil {
				t.Fatal(err)
			}
			if got != tt.want {
				t.Errorf("funcNameToPkgPath(%v) = %v, want %v", tt.f, got, tt.want)
			}
		})
	}
}
