package dto

import (
	"bytes"
	"encoding/json"
	"fmt"
	"time"
)

// QueryType 查询类型枚举
type QueryType string

const (
	QueryTypeSlowQuery  QueryType = "SLOW_QUERY"
	QueryTypeStatements QueryType = "STATEMENTS"
	QueryTypeTopSQL     QueryType = "TOP_SQL"
	QueryTypeLogStats   QueryType = "LOG_STATS"
)

// DefaultPartitionColumn 默认分区字段
const DefaultPartitionColumn = "date"

// CanonicalDataProxyQueryRequest is the strict request item accepted by the
// versioned, org/cluster-scoped SQL query APIs. Scope and data-source routing
// are intentionally absent: the handler derives them from the request path and
// Clinic's control plane.
type CanonicalDataProxyQueryRequest struct {
	SQL     string `json:"sql" binding:"required" minLength:"1" maxLength:"1048576"`
	Timeout int64  `json:"timeout,omitempty" minimum:"0" maximum:"1800"` // seconds; zero uses the service default
}

// UnmarshalJSON keeps the canonical contract exact: field names are
// case-sensitive, duplicate keys are rejected, and explicit null values do
// not silently become zero values. Legacy request unmarshalling is separate.
func (r *CanonicalDataProxyQueryRequest) UnmarshalJSON(data []byte) error {
	decoder := json.NewDecoder(bytes.NewReader(data))
	start, err := decoder.Token()
	if err != nil {
		return err
	}
	if delim, ok := start.(json.Delim); !ok || delim != '{' {
		return fmt.Errorf("canonical query item must be an object")
	}

	seen := make(map[string]struct{}, 2)
	for decoder.More() {
		keyToken, err := decoder.Token()
		if err != nil {
			return err
		}
		key, ok := keyToken.(string)
		if !ok {
			return fmt.Errorf("canonical query item contains an invalid field name")
		}
		if _, duplicate := seen[key]; duplicate {
			return fmt.Errorf("canonical query item contains duplicate field %q", key)
		}
		seen[key] = struct{}{}

		var value json.RawMessage
		if err := decoder.Decode(&value); err != nil {
			return err
		}
		if bytes.Equal(bytes.TrimSpace(value), []byte("null")) {
			return fmt.Errorf("canonical query item field %q must not be null", key)
		}
		switch key {
		case "sql":
			if err := json.Unmarshal(value, &r.SQL); err != nil {
				return err
			}
		case "timeout":
			if err := json.Unmarshal(value, &r.Timeout); err != nil {
				return err
			}
		default:
			return fmt.Errorf("canonical query item contains unknown field %q", key)
		}
	}
	if _, err := decoder.Token(); err != nil {
		return err
	}
	return nil
}

// DataProxyCapabilitiesResponse describes the stable service-level
// capabilities shared by the canonical and legacy information endpoints.
type DataProxyCapabilitiesResponse struct {
	Service          string   `json:"service"`
	Version          string   `json:"version"`
	SupportedVendors []string `json:"supported_vendors"`
}

// DataProxyQueryRequest DataProxy 统一查询请求
type DataProxyQueryRequest struct {
	SQL string `json:"sql"` // 逻辑 SQL（方言无关）
	// Type 字段已删除 - 系统会从表名自动推断

	ClusterId string `json:"clusterId"` // 集群 ID（用于动态表名和自动获取 dataSource）
	// PartitionColumns 字段已删除 - 分区字段固定为 "date"
	Timeout time.Duration         `json:"timeout"` // 查询超时时间（内部存储为 Duration，JSON 接受秒数）
	Options DataProxyQueryOptions `json:"options"` // 查询选项
}

// UnmarshalJSON 自定义反序列化，同时支持驼峰式和下划线式字段名
func (r *DataProxyQueryRequest) UnmarshalJSON(data []byte) error {
	// 定义一个临时结构体，包含所有可能的字段名
	type Alias struct {
		SQL          string                `json:"sql"`
		ClusterId    string                `json:"clusterId"`
		ClusterIdAlt string                `json:"cluster_id"` // 向后兼容
		Timeout      int64                 `json:"timeout"`    // JSON 中为秒数
		Options      DataProxyQueryOptions `json:"options"`
	}

	var tmp Alias
	if err := json.Unmarshal(data, &tmp); err != nil {
		return err
	}

	r.SQL = tmp.SQL
	r.Options = tmp.Options

	// 将秒转换为 time.Duration（纳秒）
	if tmp.Timeout > 0 {
		r.Timeout = time.Duration(tmp.Timeout) * time.Second
	}

	// ClusterId 向后兼容
	if tmp.ClusterId != "" {
		r.ClusterId = tmp.ClusterId
	} else {
		r.ClusterId = tmp.ClusterIdAlt
	}

	return nil
}

// DataProxyQueryOptions DataProxy 查询选项
type DataProxyQueryOptions struct {
	Region              string `json:"region"`              // 强制指定 Region（可选）
	Vendor              string `json:"vendor"`              // 强制指定云厂商（可选）
	DataSource          string `json:"dataSource"`          // 强制指定数据源（可选）
	SkipTableManagement bool   `json:"skipTableManagement"` // 跳过表管理（不检查表存在、不加载分区）
	SkipSQLRewrite      bool   `json:"skipSQLRewrite"`      // 跳过 SQL 方言重写（直接将 SQL 发送到引擎，调用方需自行确保 SQL 兼容目标引擎）
	ClusterId           string `json:"-"`                   // 内部传递 clusterId（用于 VIEW 依赖表的表名生成，不由外部 JSON 传入）
	ClinicTenantId      string `json:"-"`                   // 内部传递 tenantId（用于 LogStats VIEW 过滤，不由外部 JSON 传入）
}

// UnmarshalJSON 自定义反序列化，同时支持驼峰式和下划线式字段名
func (o *DataProxyQueryOptions) UnmarshalJSON(data []byte) error {
	type Alias struct {
		UseCache               bool   `json:"useCache"`
		UseCacheAlt            bool   `json:"use_cache"` // 向后兼容
		Region                 string `json:"region"`
		Vendor                 string `json:"vendor"`
		DataSource             string `json:"dataSource"`
		DataSourceAlt          string `json:"data_source"` // 向后兼容
		SkipTableManagement    bool   `json:"skipTableManagement"`
		SkipTableManagementAlt bool   `json:"skip_table_management"` // 向后兼容
		SkipSQLRewrite         bool   `json:"skipSQLRewrite"`
		SkipSQLRewriteAlt      bool   `json:"skip_sql_rewrite"` // 向后兼容
	}

	var tmp Alias
	if err := json.Unmarshal(data, &tmp); err != nil {
		return err
	}

	o.Region = tmp.Region
	o.Vendor = tmp.Vendor
	o.SkipTableManagement = tmp.SkipTableManagement || tmp.SkipTableManagementAlt
	o.SkipSQLRewrite = tmp.SkipSQLRewrite || tmp.SkipSQLRewriteAlt

	// DataSource 向后兼容
	if tmp.DataSource != "" {
		o.DataSource = tmp.DataSource
	} else if tmp.DataSourceAlt != "" {
		o.DataSource = tmp.DataSourceAlt
	}

	return nil
}

// DataProxyAuthConfig DataProxy 认证配置
type DataProxyAuthConfig struct {
	Type         string `json:"type"`          // 认证类型 (iam, explicit)
	AccessKey    string `json:"access_key"`    // 访问密钥
	SecretKey    string `json:"secret_key"`    // 密钥
	SessionToken string `json:"session_token"` // 会话令牌
	ProjectID    string `json:"project_id"`    // GCP 项目 ID
}

// DataProxyQueryResult DataProxy 统一查询结果
type DataProxyQueryResult struct {
	Columns  []string                `json:"columns"`  // 列名
	Rows     [][]interface{}         `json:"rows"`     // 数据行
	Metadata DataProxyResultMetadata `json:"metadata"` // 元数据
}

// DataProxyBatchQueryResponse is the synchronous batch response returned by
// both the canonical adapter and the existing Data Proxy query core.
type DataProxyBatchQueryResponse struct {
	Results []*DataProxyQueryResult `json:"results"`
	Count   int                     `json:"count"`
}

// DataProxyResultMetadata DataProxy 结果元数据
type DataProxyResultMetadata struct {
	RowCount            int64             `json:"rowCount"`                                           // 查询结果行数
	BytesScanned        int64             `json:"bytesScanned"`                                       // 扫描字节数
	ExecutionTime       FormattedDuration `json:"executionTime" swaggertype:"string"`                 // 执行时间（格式化为易读形式，如 "2.3s"）
	EngineExecutionTime FormattedDuration `json:"engineExecutionTime,omitempty" swaggertype:"string"` // 后端引擎执行时间
	QueryID             string            `json:"queryId"`                                            // 查询 ID（MaxCompute 为 InstanceID）
	Engine              string            `json:"engine"`                                             // 使用的引擎
	Vendor              string            `json:"vendor"`                                             // 云厂商
	Region              string            `json:"region"`                                             // Region
}

// FormattedDuration 格式化的时间段，JSON 输出为易读格式
type FormattedDuration time.Duration

// MarshalJSON 自定义 JSON 序列化，输出为 "2.3s" 格式
func (d FormattedDuration) MarshalJSON() ([]byte, error) {
	duration := time.Duration(d)
	var formatted string

	seconds := duration.Seconds()
	if seconds < 1 {
		// 小于1秒，显示毫秒
		formatted = fmt.Sprintf("%.0fms", duration.Seconds()*1000)
	} else if seconds < 60 {
		// 小于60秒，显示秒（保留1位小数）
		formatted = fmt.Sprintf("%.1fs", seconds)
	} else {
		// 大于60秒，显示分钟和秒
		minutes := int(seconds / 60)
		remainingSeconds := seconds - float64(minutes*60)
		formatted = fmt.Sprintf("%dm%.0fs", minutes, remainingSeconds)
	}

	return json.Marshal(formatted)
}

// SchemaRequest 表 Schema 查询请求（支持批量查询）
type SchemaRequest struct {
	Tables    []string              `json:"tables" form:"tables"`       // 表名列表（必填，支持多个表）
	ClusterId string                `json:"clusterId" form:"clusterId"` // 集群 ID（必填，用于自动拼接表名和获取 dataSource/region）
	Options   DataProxyQueryOptions `json:"options" form:"options"`     // 查询选项（包含 dataSource 和 region，可选）
}

// SchemaResponse 单表 Schema 查询响应
type SchemaResponse struct {
	Database   string         `json:"database"`          // 数据库名
	Table      string         `json:"table"`             // 表名
	Columns    []ColumnInfo   `json:"columns"`           // 列信息列表
	Partitions []PartitionDef `json:"partitions"`        // 分区定义列表
	DataSource string         `json:"dataSource"`        // 数据源 URI
	Location   string         `json:"location"`          // 表的 S3 存储位置
	IsView     bool           `json:"is_view,omitempty"` // 是否为 VIEW
}

// BatchSchemaResponse 批量 Schema 查询响应
type BatchSchemaResponse struct {
	Schemas []SchemaResponse `json:"schemas"` // Schema 列表
	Count   int              `json:"count"`   // Schema 数量
}

// ColumnInfo 列信息
type ColumnInfo struct {
	Name    string `json:"name"`              // 列名
	Type    string `json:"type"`              // 数据类型
	Comment string `json:"comment,omitempty"` // 列注释
}

// PartitionDef 分区定义
type PartitionDef struct {
	Name string `json:"name"` // 分区字段名
	Type string `json:"type"` // 分区字段类型
}
