import json

import requests

PREREQUISITE_PROMPT = """\
あなたは採点者です。

問題, 採点基準, 回答 が与えられます。
回答を1,2,3,4,5の5段階で採点し、数字のみを出力してください。

# 採点基準
基本的な採点基準
- 1点: 誤っている、 指示に従えていない
- 2点: 誤っているが、方向性は合っている
- 3点: 部分的に誤っている、 部分的に合っている
- 4点: 合っている
- 5点: 役に立つ

基本的な減点項目
- 不自然な日本語: -1点
- 部分的に事実と異なる内容を述べている: -1点
"""


def evaluation_prompt(
    input: str, output: str, eval_aspect: str | None, target: str | None
) -> str:
    return f"""\
回答を1,2,3,4,5の5段階で採点し、数字のみを出力してください。

# 問題: {input}

{f"# 正解例: {target}" if target is not None else ""}

{f"# 採点基準: {eval_aspect}" if eval_aspect is not None else ""}

# 回答: {output}
"""


# GradioからのGemini SDKを用いた通信がいつまでも終わらないため、REST APIを利用する
def evaluate(results: list[dict], api_key: str, batch_size: int = 10) -> list[dict]:
    url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key={api_key}"
    headers = {"Content-Type": "application/json"}

    evaluations = []
    for i in range(0, len(results), batch_size):
        batch_results = results[i : i + batch_size]

        prompts = [
            evaluation_prompt(
                result["input"],
                result["output"],
                result.get("eval_aspect"),
                result.get("target"),
            )
            for result in batch_results
        ]

        data = {
            "contents": [{"parts": [{"text": "\n".join(prompts)}]}],
            "generationConfig": {
                "response_mime_type": "application/json",
                "response_schema": {"type": "ARRAY", "items": {"type": "NUMBER"}},
            },
        }

        response = requests.post(url, headers=headers, data=json.dumps(data))

        if response.status_code == 200:
            response_data = response.json()
            # Parse the response_data to extract the scores
            scores = json.loads(
                response_data["candidates"][0]["content"]["parts"][0]["text"]
            )
        else:
            raise Exception(
                f"API request failed with status code {response.status_code}: {response.text}"
            )

        for result, score in zip(batch_results, scores):
            evaluation = {
                "input": result["input"],
                "output": result["output"],
                "score": score,
            }
            if "eval_aspect" in result:
                evaluation["eval_aspect"] = result["eval_aspect"]
            if "target" in result:
                evaluation["target"] = result["target"]
            evaluations.append(evaluation)

    return evaluations


def report(tasks: list[dict]) -> str:
    return (
        """\
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>レポート</title>
    <style>
        body {
            background-color: #f8f9fa;
        }
        .container {
            width: 80%; /* 可変幅 */
            margin: 20px auto;
            background-color: #ffffff;
            border-radius: 8px;
        }
        .divider {
            position: relative;
            padding: 16px 0;
            align-items: center;
            justify-content: center;
        }
        .divider .line {
            height: 1px;
            background-color: #ddd;
        }
        .divider .taskName {
            position: absolute;
            margin: -8px;
            left: 50%;
            transform: translateX(-50%);
            padding: 0 10px;
            font-size: 14px;
            font-weight: 900;
            text-align: center;
            border: 1px solid #ddd;
            border-radius: 9999px;
            background-color: #ffffff;
            white-space: nowrap;
        }
        .message {
            padding: 8px;
        }
        .content {
            font-size: 14px;
            font-weight: 400;
        }
        .from {
            font-size: 14px;
            font-weight: 900;
        }
    </style>
</head>
<body>
    <div class="container" id="container"></div>
    <script>
        const messages = """
        + json.dumps(tasks)
        + """;

        // taskName: str
        const createDivider = (taskName) => {
            const divider = document.createElement('div');
            divider.classList.add('divider');

            const line = document.createElement('div');
            line.classList.add('line');

            const taskNameLabel = document.createElement('div');
            taskNameLabel.classList.add('taskName');
            taskNameLabel.textContent = taskName;

            divider.appendChild(line);
            divider.appendChild(taskNameLabel);

            return divider;
        };

        // task: HTMLDivElement, from: 'input' | 'output' | str, text: string
        // return: HTMLDivElement
        const createMessage = (text, name) => {
            const message = document.createElement('div');
            message.classList.add('message');

            const from = document.createElement('div');
            from.classList.add('from');
            from.textContent = name;

            const content = document.createElement('div');
            content.classList.add('content');
            content.innerHTML = text.replace(/\\n/g, '<br>');

            message.appendChild(from);
            message.appendChild(content);

            return message;
        };

        const container = document.getElementById('container');

        messages.forEach((message, i) => {
            const task = document.createElement('div');
            task.classList.add('task');

            task.appendChild(createDivider(message.task_id ? `Task ID: ${message.task_id}` : `Task Index ${i}`));
            task.appendChild(createMessage(message.input, 'input'));
            task.appendChild(createMessage(message.output, 'output' + (message.score ? ` (score: ${message.score})` : '')));

            container.appendChild(task);
        });
    </script>
</body>
</html>
"""
    )