/**
 * Copyright 2025 ByteDance Inc.
 *
 * 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
 *
 *     https://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.
 */

package writer

import (
	"bytes"
	"os"
	"reflect"
	"testing"

	"github.com/cloudwego/abcoder/lang/testutils"
	"github.com/cloudwego/abcoder/lang/uniast"
)

func TestWriter_WriteRepo(t *testing.T) {
	astFile := testutils.GetTestAstFile("localsession")
	repo, err := uniast.LoadRepo(astFile)
	if err != nil {
		t.Fatal(err)
	}
	type fields struct {
		Options Options
	}
	type args struct {
		repo *uniast.Repository
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		wantErr bool
	}{
		{
			name: "test",
			fields: fields{
				Options: Options{
					CompilerPath: "true", // DO NOT RUN go mod tidy
				},
			},
			args:    args{repo: repo},
			wantErr: false,
		},
	}
	tmproot := testutils.MakeTmpTestdir(true)
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			w := NewWriter(tt.fields.Options)
			if err := w.WriteRepo(tt.args.repo, tmproot); (err != nil) != tt.wantErr {
				t.Errorf("Writer.WriteRepo() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestPatcher_PatchImports(t *testing.T) {
	repoDir, err := testutils.GitCloneFast("github.com/cloudwego/localsession", "localsession", "main")
	if err != nil {
		t.Errorf("fail to clone repo %v", err)
	}
	glsFile := repoDir + "/gls.go"
	data, err := os.ReadFile(glsFile)
	if err != nil {
		t.Errorf("fail read file %v file: %s", err, glsFile)
		return
	}
	alias1 := string("_")
	data1 := bytes.Replace(data, []byte(`import (
	"fmt"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)
`), []byte(`import (
	"fmt"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
	_ "runtime"
)
`), 1)

	type args struct {
		file *uniast.File
	}
	tests := []struct {
		name    string
		args    args
		want    []byte
		wantErr bool
	}{
		{
			name: "empty new",
			args: args{
				file: &uniast.File{
					Imports: []uniast.Import{},
					Path:    glsFile,
				},
			},
			want:    data,
			wantErr: false,
		},
		{
			name: "add",
			args: args{
				file: &uniast.File{
					Imports: []uniast.Import{
						{
							Path:  `"runtime"`,
							Alias: &alias1,
						},
					},
					Path: glsFile,
				},
			},
			want:    data1,
			wantErr: false,
		},
	}
	for _, tt := range tests {
		p := NewWriter(Options{})
		t.Run(tt.name, func(t *testing.T) {
			old, err := os.ReadFile(tt.args.file.Path)
			if err != nil {
				println("wtf", tt.args.file.Path)
				t.Errorf("fail read file %v file: %s", err, tt.args.file.Path)
				return
			}
			got, err := p.PatchImports(tt.args.file.Imports, old)
			if (err != nil) != tt.wantErr {
				t.Errorf("Patcher.PatchImports() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Patcher.PatchImports() = %s, want %s", got, tt.want)
			}
		})
	}
}
