package prompt

import (
	"agent/src/message"
	"fmt"
	"strings"
)

var prompt_unittest_more = replaceWithBacktick(
`You're an advanced AI test generator.

You're about to write test cases for the function `+"`{%s}`"+" in the file `{%s}`."+`
Before you start, you need to check if you have enough context information to write the test cases.

Here is the source code of the function:

"""
{%s}
"""

And here are some context information that might help you write the test cases:


{%s}


Do you think the context information is enough?
If the information is insufficient, recommend which symbols or types you need to know more about.

Return a JSON object with a single key "key_symbols" whose value is a list of strings.
- If the context information is enough, return an empty list.
- Each string is the name of a symbol or type appearing in the function that lacks context information for writing test.
- The list should contain the most important symbols and should not exceed 10 items.

JSON Format Example:
{{
    "key_symbols": ["<symbol 1>", "<symbol 2>", "<symbol 3>",...]
}}

`)


func MakeExecUnitTestMore(req *message.RequestExecUnitTestRecommend) (string, error) {
	function_content, err := req.GetContent(&req.FuncLocation)
	if err != nil {
		return "", err
	}
	
	locations := make(map[string]bool)
	var context_contents []string
	var content string
	req.FuncSymbols.Iter(func(sm message.Symbol)bool{
		if !locations[sm.Name] {
			content, err = req.GetContent(&req.FuncLocation)
			if err != nil {
				return true
			}
			context_contents = append(context_contents,
				fmt.Sprintf("file path:`%s`\n```%s```\n", req.FilePath, content),
			)
			locations[sm.Name] = true
		}
		return false
	})
	if err != nil {
		return "", err
	}

	s := fmt.Sprintf(prompt_unittest_more, req.FuncName, req.FilePath, function_content, strings.Join(context_contents, "\n"))
	return s, nil	
}


var prompt_unittest_recommend = replaceWithBacktick(
`You're an advanced AI test case generator.
Given a user prompt and a target function, propose detailed test cases for the function based on the prompt, categorizing each as either a 'happy path' or an 'edge case'.

The user prompt is as follows:

{%s}

The target function is {%s}, located in the file {%s}.

Here's the relevant source code of the function:

{%s}

For each test case, provide a description that includes:
- A brief explanation of the test's purpose
- The specific conditions being tested.
- The expected outcome the test is verifying.
Each description should be a single sentence, as concise as possible.

Categorize each test case as:
- 'happy path': Tests the function with typical inputs and standard conditions, ensuring it performs as expected in normal use.
- 'edge case': Tests the function with atypical inputs or in unusual conditions, checking its robustness and error handling.

You don't have to write the test cases in code, just describe them in plain {chat_language}.

Aim to generate 3 'happy path' test cases and 3 'edge case' test cases, totaling 6 test cases.

Answer in JSON format:
{{
    "test_cases": [
        {{"description": "<describe test case 1 in {chat_language}>", "category": "happy path"}},
        ...
        {{"description": "<describe test case 4 in {chat_language}>", "category": "edge case"}},
        ...
    ]
}}
`)

func MakeExecUnitTestRecommend(req *message.RequestExecUnitTestRecommend) (string, error) {
	function_content, err := req.GetContent(&req.FuncLocation)
	if err != nil {
		return "", err
	}
	
	locations := make(map[string]bool)
	var context_contents []string
	var content string
	req.FuncSymbols.Iter(func(sm message.Symbol)bool{
		if !locations[sm.Name] {
			content, err = req.GetContent(&req.FuncLocation)
			if err != nil {
				return true
			}
			context_contents = append(context_contents,
				fmt.Sprintf("file path:`%s`\n```%s```\n", req.FilePath, content),
			)
			locations[sm.Name] = true
		}
		return false
	})
	if err != nil {
		return "", err
	}

	s := fmt.Sprintf(prompt_unittest_more, req.FuncName, req.FilePath, function_content, strings.Join(context_contents, "\n"))
	return s, nil	
}
