package system

import (
	"errors"

	"kra/pkg/database/migration"

	"gorm.io/gorm"
)

// Migrations returns schema steps owned by the built-in system module.
// Administrators, menus, APIs, and policies are created only by SeedSystem
// during the explicit first-install flow.
func Migrations() []migration.Step {
	return []migration.Step{
		{
			ID: "202608200002_system_schema",
			Migrate: func(db *gorm.DB) error {
				return migration.CreateMissingTables(db,
					&userPO{}, &authorityPO{}, &menuPO{}, &userAuthorityPO{}, &authorityMenuPO{}, &menuParameterPO{},
					&apiPO{}, &ignoredAPIPO{}, &authorityAPIPO{}, &casbinRulePO{}, &menuButtonPO{}, &authorityButtonPO{},
					&departmentPO{}, &positionPO{}, &userDepartmentPO{}, &userPositionPO{}, &authorityDepartmentPO{},
					&dictionaryPO{}, &dictionaryDetailPO{}, &parameterPO{}, &apiTokenPO{}, &jwtBlacklistPO{}, &SecurityConfigPO{},
					&versionPO{}, &exportTemplatePO{}, &exportConditionPO{}, &exportJoinPO{},
					&operationPO{}, &loginLogPO{}, &DataAccessLogPO{}, &errorRecordPO{},
					&mediaPO{}, &categoryPO{}, &uploadSessionPO{}, &uploadChunkPO{},
					&announcementPO{},
				)
			},
		},
		{ID: "202608210002_communication_surface", Migrate: ensureCommunicationSurface},
		{ID: "202608210003_communication_test_surface", Migrate: ensureCommunicationTestSurface},
	}
}

func ensureCommunicationSurface(db *gorm.DB) error {
	if db == nil || !db.Migrator().HasTable(&menuPO{}) || !db.Migrator().HasTable(&apiPO{}) {
		return nil
	}

	return db.Transaction(func(tx *gorm.DB) error {
		var parent menuPO
		if err := tx.Where("name = ?", "extensions").First(&parent).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil
			}
			return err
		}

		menu := menuPO{
			MenuLevel: 1,
			ParentID:  parent.ID,
			Path:      "integrationConfig",
			Name:      "integrationConfig",
			Component: "view/systemTools/integration/config.vue",
			Title:     "通信集成",
			Icon:      "connection",
			Sort:      8,
		}
		var current menuPO
		err := tx.Where("name = ?", menu.Name).First(&current).Error
		switch {
		case errors.Is(err, gorm.ErrRecordNotFound):
			if err = tx.Create(&menu).Error; err != nil {
				return err
			}
		case err != nil:
			return err
		default:
			if err = tx.Model(&current).Updates(map[string]any{
				"menu_level": menu.MenuLevel,
				"parent_id":  menu.ParentID,
				"path":       menu.Path,
				"component":  menu.Component,
				"title":      menu.Title,
				"icon":       menu.Icon,
				"sort":       menu.Sort,
			}).Error; err != nil {
				return err
			}
			menu.ID = current.ID
		}

		apis := []apiPO{
			{Path: "/integration/configs/:kind", Method: "GET", APIGroup: "集成配置", Description: "按类型获取集成配置"},
			{Path: "/integration/configs/:kind/:provider", Method: "GET", APIGroup: "集成配置", Description: "获取指定集成配置"},
			{Path: "/integration/configs/:kind/:provider", Method: "PUT", APIGroup: "集成配置", Description: "保存集成配置"},
			{Path: "/integration/configs/:kind/:provider/test", Method: "POST", APIGroup: "集成配置", Description: "测试通信集成连接"},
			{Path: "/integration/configs/:kind/:provider", Method: "DELETE", APIGroup: "集成配置", Description: "删除集成配置"},
		}
		for _, api := range apis {
			if err := tx.Where("path = ? AND method = ?", api.Path, api.Method).FirstOrCreate(&api).Error; err != nil {
				return err
			}
		}

		if !tx.Migrator().HasTable(&authorityPO{}) || !tx.Migrator().HasTable(&authorityMenuPO{}) || !tx.Migrator().HasTable(&casbinRulePO{}) {
			return nil
		}
		var authority authorityPO
		if err := tx.Where("authority_id = ?", 888).First(&authority).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil
			}
			return err
		}
		var linkCount int64
		if err := tx.Model(&authorityMenuPO{}).Where("sys_authority_authority_id = ? AND sys_base_menu_id = ?", authority.AuthorityID, menu.ID).Count(&linkCount).Error; err != nil {
			return err
		}
		if linkCount == 0 {
			if err := tx.Create(&authorityMenuPO{SysAuthorityAuthorityID: authority.AuthorityID, SysBaseMenuID: menu.ID}).Error; err != nil {
				return err
			}
		}
		for _, api := range apis {
			exists, err := policyExists(tx, authority.AuthorityID, api.Path, api.Method)
			if err != nil {
				return err
			}
			if !exists {
				rule := newPolicyRule(authority.AuthorityID, api.Path, api.Method)
				if err := tx.Create(&rule).Error; err != nil {
					return err
				}
			}
		}
		return nil
	})
}

func ensureCommunicationTestSurface(db *gorm.DB) error {
	if db == nil || !db.Migrator().HasTable(&menuPO{}) || !db.Migrator().HasTable(&apiPO{}) {
		return nil
	}

	return db.Transaction(func(tx *gorm.DB) error {
		var existingMenus int64
		if err := tx.Model(&menuPO{}).Where("name IN ?", []string{"extensions", "integrationConfig"}).Count(&existingMenus).Error; err != nil {
			return err
		}
		if existingMenus == 0 {
			return nil
		}
		api := apiPO{
			Path:        "/integration/configs/:kind/:provider/test",
			Method:      "POST",
			APIGroup:    "集成配置",
			Description: "测试通信集成连接",
		}
		if err := tx.Where("path = ? AND method = ?", api.Path, api.Method).FirstOrCreate(&api).Error; err != nil {
			return err
		}
		if !tx.Migrator().HasTable(&authorityPO{}) || !tx.Migrator().HasTable(&casbinRulePO{}) {
			return nil
		}
		var authority authorityPO
		if err := tx.Where("authority_id = ?", 888).First(&authority).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil
			}
			return err
		}
		exists, err := policyExists(tx, authority.AuthorityID, api.Path, api.Method)
		if err != nil {
			return err
		}
		if exists {
			return nil
		}
		rule := newPolicyRule(authority.AuthorityID, api.Path, api.Method)
		return tx.Create(&rule).Error
	})
}
