// Package app 承载 user-service App 注册表的 MySQL 持久化。
package app

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

	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	userdomain "hyapp/services/user-service/internal/domain/user"
)

// Repository 读取 apps 注册表，供 gateway 把包名解析成内部 app_code。
type Repository struct {
	db *sql.DB
}

func New(db *sql.DB) *Repository {
	return &Repository{db: db}
}

// ResolveApp 按 app_code 或 package_name/platform 读取 active App。
func (r *Repository) ResolveApp(ctx context.Context, code string, packageName string, platform string) (userdomain.App, error) {
	if r == nil || r.db == nil {
		return userdomain.App{}, xerr.New(xerr.Unavailable, "app repository is not configured")
	}
	code = strings.TrimSpace(code)
	if code != "" {
		code = appcode.Normalize(code)
	}
	packageName = strings.TrimSpace(packageName)
	platform = strings.ToLower(strings.TrimSpace(platform))

	var row *sql.Row
	if code != "" {
		row = r.db.QueryRowContext(ctx, `
			SELECT app_id, app_code, app_name, package_name, platform, status, created_at_ms, updated_at_ms
			FROM apps
			WHERE app_code = ? AND status = ?
			LIMIT 1
		`, code, userdomain.AppStatusActive)
	} else if packageName != "" {
		// gateway 首次请求通常只有包名；平台为空时允许命中任意平台配置，便于开发期客户端逐步补齐 header。
		if platform == "" {
			row = r.db.QueryRowContext(ctx, `
				SELECT app_id, app_code, app_name, package_name, platform, status, created_at_ms, updated_at_ms
				FROM apps
				WHERE package_name = ? AND status = ?
				ORDER BY platform DESC
				LIMIT 1
			`, packageName, userdomain.AppStatusActive)
		} else {
			row = r.db.QueryRowContext(ctx, `
				SELECT app_id, app_code, app_name, package_name, platform, status, created_at_ms, updated_at_ms
				FROM apps
				WHERE package_name = ? AND (platform = ? OR platform = '') AND status = ?
				ORDER BY CASE WHEN platform = ? THEN 0 ELSE 1 END
				LIMIT 1
			`, packageName, platform, userdomain.AppStatusActive, platform)
		}
	} else {
		row = r.db.QueryRowContext(ctx, `
			SELECT app_id, app_code, app_name, package_name, platform, status, created_at_ms, updated_at_ms
			FROM apps
			WHERE app_code = ? AND status = ?
			LIMIT 1
		`, code, userdomain.AppStatusActive)
	}

	var app userdomain.App
	if err := row.Scan(&app.AppID, &app.AppCode, &app.AppName, &app.PackageName, &app.Platform, &app.Status, &app.CreatedAtMs, &app.UpdatedAtMs); err != nil {
		if err == sql.ErrNoRows {
			return userdomain.App{}, xerr.New(xerr.InvalidArgument, "app is not supported")
		}
		return userdomain.App{}, err
	}
	return app, nil
}

// ListApps 只返回 active 注册表事实；排序稳定，便于 cron 生成独立租户租约。
func (r *Repository) ListApps(ctx context.Context) ([]userdomain.App, error) {
	if r == nil || r.db == nil {
		return nil, xerr.New(xerr.Unavailable, "app repository is not configured")
	}
	rows, err := r.db.QueryContext(ctx, `
		SELECT app_id, app_code, app_name, package_name, platform, status, created_at_ms, updated_at_ms
		FROM apps
		WHERE status = ?
		ORDER BY app_code ASC`, userdomain.AppStatusActive)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	apps := make([]userdomain.App, 0)
	for rows.Next() {
		var app userdomain.App
		if err := rows.Scan(&app.AppID, &app.AppCode, &app.AppName, &app.PackageName, &app.Platform, &app.Status, &app.CreatedAtMs, &app.UpdatedAtMs); err != nil {
			return nil, err
		}
		apps = append(apps, app)
	}
	return apps, rows.Err()
}
