// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package repo

import (
	"testing"

	"gitea.dev/models/unit"
	"gitea.dev/models/unittest"
	"gitea.dev/modules/util"

	"github.com/stretchr/testify/assert"
)

func TestDefaultTargetBranchSelection(t *testing.T) {
	assert.NoError(t, unittest.PrepareTestDatabase())

	ctx := t.Context()
	repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1})

	assert.Equal(t, repo.DefaultBranch, repo.GetPullRequestTargetBranch(ctx))

	repo.Units = nil
	prUnit, err := repo.GetUnit(ctx, unit.TypePullRequests)
	assert.NoError(t, err)
	prConfig := prUnit.PullRequestsConfig()
	prConfig.DefaultTargetBranch = "branch2"
	prUnit.Config = prConfig
	assert.NoError(t, UpdateRepoUnitConfig(ctx, prUnit))
	repo.Units = nil
	assert.Equal(t, "branch2", repo.GetPullRequestTargetBranch(ctx))
}

func TestPullRequestConfigFromDB(t *testing.T) {
	cases := []struct {
		// name describes the row shape under test; the comments capture why each row matters.
		name              string
		json              string
		wantMergeUpdate   bool
		wantRebaseUpdate  bool
		wantDefaultStyle  UpdateStyle
		wantValidatesPass bool
	}{
		{
			// Empty object exercises the all-defaults path (e.g. fresh repos created via low-level paths).
			name: "defaults", json: "{}",
			wantMergeUpdate: true, wantRebaseUpdate: true,
			wantDefaultStyle: UpdateStyleMerge, wantValidatesPass: true,
		},
		{
			// Realistic upgrade case: pre-PR JSON lacks the new fields and has AllowRebaseUpdate=false.
			// Historical setting must be preserved while new fields take safe defaults.
			name:            "legacy without new fields",
			json:            `{"AllowMerge":true,"AllowRebase":true,"AllowRebaseMerge":true,"AllowSquash":true,"AllowRebaseUpdate":false}`,
			wantMergeUpdate: true, wantRebaseUpdate: false,
			wantDefaultStyle: UpdateStyleMerge, wantValidatesPass: true,
		},
		{
			// Partially-migrated row with explicit empty string must normalize so ValidateUpdateSettings passes.
			name: "empty default style", json: `{"DefaultUpdateStyle":""}`,
			wantMergeUpdate: true, wantRebaseUpdate: true,
			wantDefaultStyle: UpdateStyleMerge, wantValidatesPass: true,
		},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			cfg := new(PullRequestsConfig)
			assert.NoError(t, cfg.FromDB([]byte(tc.json)))
			assert.Equal(t, tc.wantMergeUpdate, cfg.AllowMergeUpdate)
			assert.Equal(t, tc.wantRebaseUpdate, cfg.AllowRebaseUpdate)
			assert.Equal(t, tc.wantDefaultStyle, cfg.DefaultUpdateStyle)
			if tc.wantValidatesPass {
				assert.NoError(t, cfg.ValidateUpdateSettings())
			}
		})
	}
}

func TestPullRequestConfigValidateUpdateSettingsInvalidArgument(t *testing.T) {
	cases := []struct {
		name string
		cfg  PullRequestsConfig
	}{
		{
			name: "invalid default style",
			cfg: PullRequestsConfig{
				AllowMergeUpdate:   true,
				AllowRebaseUpdate:  true,
				DefaultUpdateStyle: "invalid",
			},
		},
		{
			name: "no update style enabled",
			cfg: PullRequestsConfig{
				DefaultUpdateStyle: UpdateStyleMerge,
			},
		},
		{
			name: "default update style disabled",
			cfg: PullRequestsConfig{
				AllowRebaseUpdate:  true,
				DefaultUpdateStyle: UpdateStyleMerge,
			},
		},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			assert.ErrorIs(t, tc.cfg.ValidateUpdateSettings(), util.ErrInvalidArgument)
		})
	}
}
