package infra

import (
	"encoding/json"
	"os"
	"path/filepath"
	"testing"
)

// fixtureWellknown is the real-world JSON from the VPS wellknown container,
// with m.homeserver and org.matrix.msc4143.rtc_foci already present.
const fixtureWellknown = `{
  "m.homeserver": {
    "base_url": "https://matrix.organic-machine.com"
  },
  "org.matrix.msc4143.rtc_foci": [
    {
      "type": "livekit",
      "livekit_service_url": "https://livekit.organic-machine.com"
    }
  ]
}`

func TestWellknownOidcPatch(t *testing.T) {
	const issuer = "https://auth-af2f3d.organic-machine.com/"
	const accountURL = "https://auth-af2f3d.organic-machine.com/account"

	t.Run("patch adds key and preserves existing fields", func(t *testing.T) {
		dir := t.TempDir()
		jsonPath := filepath.Join(dir, "client")
		backupDir := filepath.Join(dir, "backups")

		if err := os.WriteFile(jsonPath, []byte(fixtureWellknown), 0o644); err != nil {
			t.Fatal(err)
		}

		res, err := WellknownOidcPatch(WellknownOidcPatchConfig{
			WellknownJsonPath: jsonPath,
			Issuer:            issuer,
			AccountURL:        accountURL,
			BackupDir:         backupDir,
			DryRun:            false,
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if !res.Modified {
			t.Error("want Modified=true, got false")
		}
		if res.BackupPath == "" {
			t.Error("want non-empty BackupPath")
		}

		// Backup must exist.
		if _, err := os.Stat(res.BackupPath); err != nil {
			t.Errorf("backup file missing: %v", err)
		}

		// Read written file and validate.
		written, err := os.ReadFile(jsonPath)
		if err != nil {
			t.Fatal(err)
		}
		var doc map[string]any
		if err := json.Unmarshal(written, &doc); err != nil {
			t.Fatalf("written file is not valid JSON: %v", err)
		}

		// New key must exist with correct values.
		auth, ok := doc["org.matrix.msc2965.authentication"]
		if !ok {
			t.Fatal("org.matrix.msc2965.authentication key missing")
		}
		authMap, ok := auth.(map[string]any)
		if !ok {
			t.Fatal("org.matrix.msc2965.authentication is not an object")
		}
		if authMap["issuer"] != issuer {
			t.Errorf("issuer: want %q, got %q", issuer, authMap["issuer"])
		}
		if authMap["account"] != accountURL {
			t.Errorf("account: want %q, got %q", accountURL, authMap["account"])
		}

		// Existing keys must be preserved.
		if _, ok := doc["m.homeserver"]; !ok {
			t.Error("m.homeserver was removed — must be preserved")
		}
		if _, ok := doc["org.matrix.msc4143.rtc_foci"]; !ok {
			t.Error("org.matrix.msc4143.rtc_foci was removed — must be preserved")
		}
	})

	t.Run("idempotent: second call returns Modified=false", func(t *testing.T) {
		dir := t.TempDir()
		jsonPath := filepath.Join(dir, "client")
		backupDir := filepath.Join(dir, "backups")

		if err := os.WriteFile(jsonPath, []byte(fixtureWellknown), 0o644); err != nil {
			t.Fatal(err)
		}

		cfg := WellknownOidcPatchConfig{
			WellknownJsonPath: jsonPath,
			Issuer:            issuer,
			AccountURL:        accountURL,
			BackupDir:         backupDir,
			DryRun:            false,
		}

		if _, err := WellknownOidcPatch(cfg); err != nil {
			t.Fatalf("first call error: %v", err)
		}

		res2, err := WellknownOidcPatch(cfg)
		if err != nil {
			t.Fatalf("second call error: %v", err)
		}
		if res2.Modified {
			t.Error("want Modified=false on second call, got true")
		}
		if res2.BackupPath != "" {
			t.Errorf("want empty BackupPath on no-op, got %q", res2.BackupPath)
		}
	})

	t.Run("dry run does not write file", func(t *testing.T) {
		dir := t.TempDir()
		jsonPath := filepath.Join(dir, "client")
		backupDir := filepath.Join(dir, "backups")

		if err := os.WriteFile(jsonPath, []byte(fixtureWellknown), 0o644); err != nil {
			t.Fatal(err)
		}

		res, err := WellknownOidcPatch(WellknownOidcPatchConfig{
			WellknownJsonPath: jsonPath,
			Issuer:            issuer,
			AccountURL:        accountURL,
			BackupDir:         backupDir,
			DryRun:            true,
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if !res.Modified {
			t.Error("want Modified=true on dry run with new key")
		}
		if res.BackupPath != "" {
			t.Errorf("want empty BackupPath on dry run, got %q", res.BackupPath)
		}

		// Original file must be untouched.
		content, _ := os.ReadFile(jsonPath)
		if string(content) != fixtureWellknown {
			t.Error("file was modified during dry run")
		}

		// BackupDir must not have been created.
		if _, err := os.Stat(backupDir); !os.IsNotExist(err) {
			t.Error("backup dir was created during dry run")
		}
	})

	t.Run("nonexistent file returns error", func(t *testing.T) {
		dir := t.TempDir()
		_, err := WellknownOidcPatch(WellknownOidcPatchConfig{
			WellknownJsonPath: filepath.Join(dir, "does_not_exist"),
			Issuer:            issuer,
			AccountURL:        accountURL,
			BackupDir:         filepath.Join(dir, "backups"),
			DryRun:            false,
		})
		if err == nil {
			t.Error("want error for nonexistent file, got nil")
		}
	})
}
