package article

import (
	"encoding/json"
	"fmt"
	"strings"
	"testing"
)

// This example covers text messages only, not full session restoration.
type Message struct {
	Role string
	Body string
}

type messagePayload struct {
	Role    string          `json:"role"`
	Content json.RawMessage `json:"content"`
}

func decodeClaude(raw []byte) (Message, error) {
	var entry struct {
		Type    string          `json:"type"`
		Message *messagePayload `json:"message"`
	}
	if err := json.Unmarshal(raw, &entry); err != nil {
		return Message{}, err
	}
	if entry.Message == nil {
		return Message{}, fmt.Errorf("missing message")
	}
	return normalize(entry.Type, entry.Message.Content, "text")
}

func decodePi(raw []byte) (Message, error) {
	var entry struct {
		Type    string          `json:"type"`
		Message *messagePayload `json:"message"`
	}
	if err := json.Unmarshal(raw, &entry); err != nil {
		return Message{}, err
	}
	if entry.Type != "message" || entry.Message == nil {
		return Message{}, fmt.Errorf("not a message entry")
	}
	return normalize(entry.Message.Role, entry.Message.Content, "text")
}

func decodeCodex(raw []byte) (Message, error) {
	var entry struct {
		Type    string `json:"type"`
		Payload struct {
			Type string `json:"type"`
			messagePayload
		} `json:"payload"`
	}
	if err := json.Unmarshal(raw, &entry); err != nil {
		return Message{}, err
	}
	if entry.Type != "response_item" || entry.Payload.Type != "message" {
		return Message{}, fmt.Errorf("not a response message")
	}
	return normalize(entry.Payload.Role, entry.Payload.Content, "input_text", "output_text")
}

func normalize(role string, raw json.RawMessage, textTypes ...string) (Message, error) {
	if role != "user" && role != "assistant" {
		return Message{}, fmt.Errorf("unsupported role: %q", role)
	}
	var body string
	if err := json.Unmarshal(raw, &body); err != nil {
		var blocks []struct {
			Type string `json:"type"`
			Text string `json:"text"`
		}
		if err := json.Unmarshal(raw, &blocks); err != nil {
			return Message{}, err
		}
		var parts []string
		for _, block := range blocks {
			for _, textType := range textTypes {
				if block.Type == textType && block.Text != "" {
					parts = append(parts, block.Text)
					break
				}
			}
		}
		body = strings.Join(parts, "\n")
	}
	if strings.TrimSpace(body) == "" {
		return Message{}, fmt.Errorf("no text content")
	}
	return Message{Role: role, Body: body}, nil
}

const claudeJSON = `{
  "type": "user",
  "message": {
    "role": "user",
    "content": "こんにちは"
  }
}`

const codexJSON = `{
  "type": "response_item",
  "payload": {
    "type": "message",
    "role": "user",
    "content": [
      {
        "type": "input_text",
        "text": "こんにちは"
      }
    ]
  }
}`

const piJSON = `{
  "type": "message",
  "message": {
    "role": "user",
    "content": "こんにちは"
  }
}`

func TestNormalize(t *testing.T) {
	cases := []struct {
		name   string
		raw    string
		decode func([]byte) (Message, error)
	}{
		{"Claude Code", claudeJSON, decodeClaude},
		{"Codex", codexJSON, decodeCodex},
		{"Pi", piJSON, decodePi},
	}
	want := Message{Role: "user", Body: "こんにちは"}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			got, err := tc.decode([]byte(tc.raw))
			if err != nil {
				t.Fatal(err)
			}
			if got != want {
				t.Errorf("got %#v, want %#v", got, want)
			}
		})
	}
}
