// Package appconfig 读取后台管理维护的 App 运行时配置。
package appconfig

import (
	"context"
	"database/sql"
	"errors"
	"strings"

	_ "github.com/go-sql-driver/mysql"
)

const h5LinkGroup = "h5-links"

const listH5LinksSQL = "SELECT `key`, COALESCE(value, ''), updated_at_ms FROM admin_app_configs WHERE `group` = ?"
const listAppBannersSQL = `
	SELECT id, app_code, cover_url, banner_type, param, platform, sort_order, region_id, country_code, description, updated_at_ms
	FROM admin_app_banners
	WHERE app_code = ? AND status = 'active'
	  AND (? = '' OR platform = ?)
	  AND (region_id = 0 OR region_id = ?)
	  AND (country_code = '' OR country_code = ?)
	ORDER BY sort_order ASC, id DESC`
const latestAppVersionSQL = `
	SELECT id, app_code, platform, version, build_number, force_update, download_url, COALESCE(description, ''), updated_at_ms
	FROM admin_app_versions
	WHERE app_code = ? AND platform = ?
	ORDER BY build_number DESC, id DESC
	LIMIT 1`

// H5Link 是 gateway 下发给 App 的 H5 入口配置。
type H5Link struct {
	Key         string `json:"key"`
	Label       string `json:"label"`
	URL         string `json:"url"`
	UpdatedAtMs int64  `json:"updated_at_ms"`
}

// BannerQuery 是 App 首页 banner 的公开筛选条件。
type BannerQuery struct {
	AppCode  string
	Platform string
	RegionID int64
	Country  string
}

// Banner 是 gateway 下发给 App 首页的 banner 配置。
type Banner struct {
	ID          uint   `json:"id"`
	CoverURL    string `json:"cover_url"`
	BannerType  string `json:"type"`
	Param       string `json:"param"`
	Platform    string `json:"platform"`
	SortOrder   int    `json:"sort_order"`
	RegionID    int64  `json:"region_id,omitempty"`
	CountryCode string `json:"country_code,omitempty"`
	Description string `json:"description,omitempty"`
	UpdatedAtMs int64  `json:"updated_at_ms"`
}

// VersionQuery 是 App 检查更新的公开筛选条件。
type VersionQuery struct {
	AppCode            string
	Platform           string
	CurrentBuildNumber int64
}

// Version 是后台 APP配置/版本管理 中当前平台的最新 App 版本。
type Version struct {
	ID          uint   `json:"id"`
	AppCode     string `json:"app_code"`
	Platform    string `json:"platform"`
	Version     string `json:"version"`
	BuildNumber int64  `json:"build_number"`
	ForceUpdate bool   `json:"force_update"`
	DownloadURL string `json:"download_url"`
	Description string `json:"description"`
	UpdatedAtMs int64  `json:"updated_at_ms"`
}

// Reader 是 HTTP 层读取 H5 配置的最小依赖。
type Reader interface {
	ListH5Links(ctx context.Context) ([]H5Link, error)
	ListBanners(ctx context.Context, query BannerQuery) ([]Banner, error)
	LatestVersion(ctx context.Context, query VersionQuery) (Version, error)
}

type h5LinkDefinition struct {
	Key   string
	Label string
}

var h5LinkDefinitions = []h5LinkDefinition{
	{Key: "host-center", Label: "Host Center"},
	{Key: "bd-center", Label: "BD Center"},
	{Key: "bd-leader-center", Label: "BD Leader Center"},
	{Key: "agency-center", Label: "Agency Center"},
	{Key: "invite-user", Label: "Invite User"},
}

// MySQLReader 从 hyapp_admin.admin_app_configs 读取后台 H5 配置。
type MySQLReader struct {
	db *sql.DB
}

// OpenMySQLReader 创建后台配置只读连接池。
func OpenMySQLReader(dsn string) (*MySQLReader, error) {
	db, err := sql.Open("mysql", strings.TrimSpace(dsn))
	if err != nil {
		return nil, err
	}

	return &MySQLReader{db: db}, nil
}

// Close 关闭后台配置连接池。
func (r *MySQLReader) Close() error {
	if r == nil || r.db == nil {
		return nil
	}

	return r.db.Close()
}

// ListH5Links 返回固定 H5 入口集合；未配置的入口保留空 URL，方便客户端按 key 稳定渲染。
func (r *MySQLReader) ListH5Links(ctx context.Context) ([]H5Link, error) {
	if r == nil || r.db == nil {
		return nil, errors.New("app config reader is not configured")
	}

	rows, err := r.db.QueryContext(ctx, listH5LinksSQL, h5LinkGroup)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	configs := make(map[string]H5Link, len(h5LinkDefinitions))
	for rows.Next() {
		var key string
		var url string
		var updatedAtMS int64
		if err := rows.Scan(&key, &url, &updatedAtMS); err != nil {
			return nil, err
		}

		key = strings.TrimSpace(key)
		link := H5Link{
			Key: key,
			URL: strings.TrimSpace(url),
		}
		link.UpdatedAtMs = updatedAtMS
		configs[key] = link
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}

	items := make([]H5Link, 0, len(h5LinkDefinitions))
	for _, definition := range h5LinkDefinitions {
		item := H5Link{
			Key:   definition.Key,
			Label: definition.Label,
		}
		if config, ok := configs[definition.Key]; ok {
			item.URL = config.URL
			item.UpdatedAtMs = config.UpdatedAtMs
		}
		items = append(items, item)
	}

	return items, nil
}

// ListBanners 返回当前 App、平台和地域可见的首页 banner。
func (r *MySQLReader) ListBanners(ctx context.Context, query BannerQuery) ([]Banner, error) {
	if r == nil || r.db == nil {
		return nil, errors.New("app config reader is not configured")
	}

	appCode := normalizeAppCode(query.AppCode)
	platform := normalizePlatform(query.Platform)
	country := normalizeCountry(query.Country)
	rows, err := r.db.QueryContext(ctx, listAppBannersSQL, appCode, platform, platform, query.RegionID, country)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	items := make([]Banner, 0)
	for rows.Next() {
		var item Banner
		var appCode string
		var updatedAtMS int64
		if err := rows.Scan(
			&item.ID,
			&appCode,
			&item.CoverURL,
			&item.BannerType,
			&item.Param,
			&item.Platform,
			&item.SortOrder,
			&item.RegionID,
			&item.CountryCode,
			&item.Description,
			&updatedAtMS,
		); err != nil {
			return nil, err
		}
		item.UpdatedAtMs = updatedAtMS
		items = append(items, item)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

// LatestVersion 返回指定 App 和平台的最高 build_number 版本；未配置时返回空版本，方便 App 端按无更新处理。
func (r *MySQLReader) LatestVersion(ctx context.Context, query VersionQuery) (Version, error) {
	if r == nil || r.db == nil {
		return Version{}, errors.New("app config reader is not configured")
	}

	var item Version
	err := r.db.QueryRowContext(ctx, latestAppVersionSQL, normalizeAppCode(query.AppCode), normalizePlatform(query.Platform)).Scan(
		&item.ID,
		&item.AppCode,
		&item.Platform,
		&item.Version,
		&item.BuildNumber,
		&item.ForceUpdate,
		&item.DownloadURL,
		&item.Description,
		&item.UpdatedAtMs,
	)
	if errors.Is(err, sql.ErrNoRows) {
		return Version{AppCode: normalizeAppCode(query.AppCode), Platform: normalizePlatform(query.Platform)}, nil
	}
	if err != nil {
		return Version{}, err
	}
	return item, nil
}

// StaticReader 给测试和临时环境提供内存版 H5 配置读取。
type StaticReader struct {
	Links   []H5Link
	Banners []Banner
	Version Version
	Err     error
}

// ListH5Links 返回预置 H5 配置。
func (r StaticReader) ListH5Links(context.Context) ([]H5Link, error) {
	if r.Err != nil {
		return nil, r.Err
	}

	out := make([]H5Link, len(r.Links))
	copy(out, r.Links)
	return out, nil
}

// ListBanners 返回预置 App banner 配置。
func (r StaticReader) ListBanners(context.Context, BannerQuery) ([]Banner, error) {
	if r.Err != nil {
		return nil, r.Err
	}

	out := make([]Banner, len(r.Banners))
	copy(out, r.Banners)
	return out, nil
}

// LatestVersion 返回预置版本配置。
func (r StaticReader) LatestVersion(_ context.Context, query VersionQuery) (Version, error) {
	if r.Err != nil {
		return Version{}, r.Err
	}
	item := r.Version
	if item.AppCode == "" {
		item.AppCode = normalizeAppCode(query.AppCode)
	}
	if item.Platform == "" {
		item.Platform = normalizePlatform(query.Platform)
	}
	return item, nil
}

func normalizeAppCode(value string) string {
	value = strings.ToLower(strings.TrimSpace(value))
	if value == "" {
		return "lalu"
	}
	return value
}

func normalizePlatform(value string) string {
	return strings.ToLower(strings.TrimSpace(value))
}

func normalizeCountry(value string) string {
	return strings.ToUpper(strings.TrimSpace(value))
}
