package system

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"regexp"
	"strings"
	"time"
)

var (
	exportIdentifierPattern = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)?$`)
	exportParameterPattern  = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`)
	exportColumnPattern     = regexp.MustCompile(`(?i)^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)?(\s+AS\s+[A-Za-z_][A-Za-z0-9_]*)?$`)
	exportJoinOnPattern     = regexp.MustCompile(`(?i)^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*\s*=\s*[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*(\s+AND\s+[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*\s*=\s*[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*)*$`)
)

type ExportCondition struct {
	ID                   uint
	CreatedAt, UpdatedAt time.Time
	TemplateID           string
	From, Column         string
	Operator             string
}
type ExportJoin struct {
	ID                   uint
	CreatedAt, UpdatedAt time.Time
	TemplateID           string
	Join, Table, On      string
}
type ExportTemplate struct {
	ID                                                                uint
	CreatedAt                                                         time.Time
	UpdatedAt                                                         time.Time
	DBName, Name, TableName, TemplateID, TemplateInfo, SQL, ImportSQL string
	Limit                                                             *int
	Order                                                             string
	Conditions                                                        []ExportCondition
	Joins                                                             []ExportJoin
}
type ExportTemplateFilter struct {
	Name, TableName, TemplateID  string
	StartCreatedAt, EndCreatedAt *time.Time
}
type ExportRepo interface {
	CreateExportTemplate(context.Context, *ExportTemplate) error
	UpdateExportTemplate(context.Context, *ExportTemplate) error
	DeleteExportTemplates(context.Context, []uint) error
	FindExportTemplate(context.Context, uint, string) (*ExportTemplate, error)
	ListExportTemplates(context.Context, int, int, *ExportTemplateFilter) ([]*ExportTemplate, int64, error)
	QueryExport(context.Context, *ExportTemplate, map[string]string) ([]map[string]any, string, error)
	PreviewExport(context.Context, *ExportTemplate, map[string]string) (string, error)
	ImportExportRows(context.Context, *ExportTemplate, []map[string]any) error
}
type ExportUsecase struct{ ExportRepo }

func NewExportUsecase(repo ExportRepo) *ExportUsecase { return &ExportUsecase{ExportRepo: repo} }

func ValidateExportTemplate(value *ExportTemplate) error {
	if value == nil {
		return errors.New("导出模板为空")
	}
	if strings.TrimSpace(value.Name) == "" || strings.TrimSpace(value.TemplateID) == "" {
		return errors.New("导出模板名称和模板 ID 不能为空")
	}
	if !exportIdentifierPattern.MatchString(strings.TrimSpace(value.TableName)) {
		return errors.New("导出模板表名不合法")
	}
	if strings.TrimSpace(value.DBName) != "" && !exportIdentifierPattern.MatchString(strings.TrimSpace(value.DBName)) {
		return errors.New("导出模板数据库别名不合法")
	}
	if strings.TrimSpace(value.SQL) != "" || strings.TrimSpace(value.ImportSQL) != "" {
		return errors.New("导出模板不允许自定义 SQL")
	}
	var columns map[string]string
	if err := json.Unmarshal([]byte(value.TemplateInfo), &columns); err != nil {
		return fmt.Errorf("导出模板列定义无效: %w", err)
	}
	if len(columns) == 0 {
		return errors.New("导出模板列为空")
	}
	for column := range columns {
		if !exportColumnPattern.MatchString(strings.TrimSpace(column)) {
			return fmt.Errorf("导出模板列不合法: %s", column)
		}
	}
	for _, join := range value.Joins {
		kind := strings.ToUpper(strings.Join(strings.Fields(join.Join), " "))
		switch kind {
		case "JOIN", "INNER JOIN", "LEFT JOIN", "RIGHT JOIN":
		default:
			return fmt.Errorf("导出模板 Join 类型不合法: %s", join.Join)
		}
		if !exportIdentifierPattern.MatchString(strings.TrimSpace(join.Table)) || !exportJoinOnPattern.MatchString(strings.TrimSpace(join.On)) {
			return errors.New("导出模板 Join 表或条件不合法")
		}
	}
	for _, condition := range value.Conditions {
		if !exportParameterPattern.MatchString(strings.TrimSpace(condition.From)) || !exportIdentifierPattern.MatchString(strings.TrimSpace(condition.Column)) {
			return errors.New("导出模板筛选字段不合法")
		}
		switch strings.ToUpper(strings.Join(strings.Fields(condition.Operator), " ")) {
		case "=", "!=", "<>", ">", ">=", "<", "<=", "LIKE", "IN", "NOT IN", "BETWEEN":
		default:
			return fmt.Errorf("导出模板筛选运算符不合法: %s", condition.Operator)
		}
	}
	if value.Limit != nil && (*value.Limit < 1 || *value.Limit > 100000) {
		return errors.New("导出模板行数限制必须在 1 到 100000 之间")
	}
	if order := strings.TrimSpace(value.Order); order != "" {
		parts := strings.Fields(order)
		if len(parts) > 2 || !exportIdentifierPattern.MatchString(parts[0]) {
			return errors.New("导出模板排序不合法")
		}
		if len(parts) == 2 && !strings.EqualFold(parts[1], "asc") && !strings.EqualFold(parts[1], "desc") {
			return errors.New("导出模板排序方向不合法")
		}
	}
	return nil
}

func (uc *ExportUsecase) CreateExportTemplate(ctx context.Context, value *ExportTemplate) error {
	if err := ValidateExportTemplate(value); err != nil {
		return err
	}
	return uc.ExportRepo.CreateExportTemplate(ctx, value)
}

func (uc *ExportUsecase) UpdateExportTemplate(ctx context.Context, value *ExportTemplate) error {
	if err := ValidateExportTemplate(value); err != nil {
		return err
	}
	return uc.ExportRepo.UpdateExportTemplate(ctx, value)
}
