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

package ai

import (
	"context"

	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
)

// OrgSetting stores AI configuration for an organization.
type OrgSetting struct {
	ID                   int64  `xorm:"pk autoincr"`
	OrgID                int64  `xorm:"UNIQUE NOT NULL"`
	Enabled              bool   `xorm:"NOT NULL DEFAULT true"`
	APIKeyEncrypted      string `xorm:"TEXT"`
	Model                string `xorm:"VARCHAR(50) NOT NULL DEFAULT 'claude-sonnet-4-6'"`
	RateLimitRequests    int    `xorm:"NOT NULL DEFAULT 100"`
	RateLimitTokensMonth int64  `xorm:"NOT NULL DEFAULT 5000000"`
	CreatedUnix          timeutil.TimeStamp
	UpdatedUnix          timeutil.TimeStamp
}

func init() {
	db.RegisterModel(new(OrgSetting))
	db.RegisterModel(new(RepoSetting))
	db.RegisterModel(new(UsageLog))
}

// TableName returns the table name for OrgSetting.
func (OrgSetting) TableName() string {
	return "ai_org_setting"
}

// RepoSetting stores AI configuration for a repository.
type RepoSetting struct {
	ID             int64  `xorm:"pk autoincr"`
	RepoID         int64  `xorm:"UNIQUE NOT NULL"`
	Enabled        bool   `xorm:"NOT NULL DEFAULT true"`
	AutoReview     bool   `xorm:"NOT NULL DEFAULT true"`
	Strictness     string `xorm:"VARCHAR(20) NOT NULL DEFAULT 'standard'"`
	IgnorePatterns string `xorm:"TEXT"`
	CreatedUnix    timeutil.TimeStamp
	UpdatedUnix    timeutil.TimeStamp
}

// TableName returns the table name for RepoSetting.
func (RepoSetting) TableName() string {
	return "ai_repo_setting"
}

// UsageLog records AI token usage per action.
type UsageLog struct {
	ID            int64  `xorm:"pk autoincr"`
	OrgID         int64  `xorm:"INDEX NOT NULL"`
	RepoID        int64  `xorm:"INDEX NOT NULL"`
	TriggeredByID int64
	ActionType    string `xorm:"VARCHAR(20) NOT NULL"` // review, chat, agent
	Model         string `xorm:"VARCHAR(50)"`
	TokensInput   int64
	TokensOutput  int64
	DurationMs    int64
	CreatedUnix   timeutil.TimeStamp `xorm:"INDEX"`
}

// TableName returns the table name for UsageLog.
func (UsageLog) TableName() string {
	return "ai_usage_log"
}

// GetOrgSetting returns the AI settings for an org, or nil if not configured.
func GetOrgSetting(ctx context.Context, orgID int64) (*OrgSetting, error) {
	setting := &OrgSetting{OrgID: orgID}
	has, err := db.GetEngine(ctx).Where("org_id = ?", orgID).Get(setting)
	if err != nil {
		return nil, err
	}
	if !has {
		return nil, nil
	}
	return setting, nil
}

// GetRepoSetting returns the AI settings for a repo, or nil if not configured.
func GetRepoSetting(ctx context.Context, repoID int64) (*RepoSetting, error) {
	setting := &RepoSetting{RepoID: repoID}
	has, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Get(setting)
	if err != nil {
		return nil, err
	}
	if !has {
		return nil, nil
	}
	return setting, nil
}

// CreateOrgSetting inserts a new org AI setting.
func CreateOrgSetting(ctx context.Context, setting *OrgSetting) error {
	setting.CreatedUnix = timeutil.TimeStampNow()
	setting.UpdatedUnix = timeutil.TimeStampNow()
	_, err := db.GetEngine(ctx).Insert(setting)
	return err
}

// UpdateOrgSetting updates an existing org AI setting.
func UpdateOrgSetting(ctx context.Context, setting *OrgSetting) error {
	setting.UpdatedUnix = timeutil.TimeStampNow()
	_, err := db.GetEngine(ctx).ID(setting.ID).AllCols().Update(setting)
	return err
}

// CreateRepoSetting inserts a new repo AI setting.
func CreateRepoSetting(ctx context.Context, setting *RepoSetting) error {
	setting.CreatedUnix = timeutil.TimeStampNow()
	setting.UpdatedUnix = timeutil.TimeStampNow()
	_, err := db.GetEngine(ctx).Insert(setting)
	return err
}

// UpdateRepoSetting updates an existing repo AI setting.
func UpdateRepoSetting(ctx context.Context, setting *RepoSetting) error {
	setting.UpdatedUnix = timeutil.TimeStampNow()
	_, err := db.GetEngine(ctx).ID(setting.ID).AllCols().Update(setting)
	return err
}

// LogUsage records an AI usage event.
func LogUsage(ctx context.Context, log *UsageLog) error {
	log.CreatedUnix = timeutil.TimeStampNow()
	_, err := db.GetEngine(ctx).Insert(log)
	return err
}
