package stats

import (
	"context"
	"strings"
	"time"

	"lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope"
)

type SourceIdentity struct {
	Protocol       envelope.Protocol
	SourceIP       string
	SourceEndpoint string
	SourceCode     string
	PlatformName   string
	SourceKind     string
}

func NewSourceIdentity(protocol envelope.Protocol, endpoint string) (SourceIdentity, bool) {
	sourceIP := NormalizeSourceIP(endpoint)
	if sourceIP == "" {
		return SourceIdentity{}, false
	}
	return SourceIdentity{
		Protocol:       protocol,
		SourceIP:       sourceIP,
		SourceEndpoint: strings.TrimSpace(endpoint),
	}, true
}

func NewSourceIdentityFromEnvelope(env envelope.FrameEnvelope) (SourceIdentity, bool) {
	identity, ok := NewSourceIdentity(env.Protocol, env.SourceEndpoint)
	if !ok {
		return SourceIdentity{}, false
	}
	identity.SourceCode = strings.TrimSpace(env.SourceCode)
	identity.PlatformName = strings.TrimSpace(env.PlatformName)
	identity.SourceKind = normalizeSourceKindForRead(env.SourceKind)
	return identity, true
}

func ShouldManageDataSource(identity SourceIdentity) bool {
	if strings.TrimSpace(identity.SourceIP) == "" {
		return false
	}
	if strings.TrimSpace(identity.SourceCode) != "" || strings.TrimSpace(identity.PlatformName) != "" {
		return true
	}
	return normalizeSourceKindForRead(identity.SourceKind) == "PLATFORM"
}

func NormalizeSourceIP(endpoint string) string {
	return envelope.NormalizeSourceEndpointKey(endpoint)
}

func UpsertDataSource(ctx context.Context, exec Execer, identity SourceIdentity, now time.Time) error {
	if exec == nil {
		panic("stats execer must not be nil")
	}
	if identity.SourceIP == "" {
		return nil
	}
	if now.IsZero() {
		now = time.Now()
	}
	_, err := exec.ExecContext(ctx, upsertDataSourceSQL,
		string(identity.Protocol),
		identity.SourceIP,
		identity.SourceEndpoint,
		nullableTrimmedString(identity.PlatformName),
		nullableTrimmedString(identity.SourceCode),
		sourceKindForDataSourceWrite(identity),
		now,
		now,
	)
	return err
}

func sourceKindForDataSourceWrite(identity SourceIdentity) string {
	kind := normalizeSourceKindForWrite(identity.SourceKind)
	if kind != "UNKNOWN" {
		return kind
	}
	if strings.TrimSpace(identity.SourceCode) != "" || strings.TrimSpace(identity.PlatformName) != "" {
		return "PLATFORM"
	}
	return "UNKNOWN"
}

const upsertDataSourceSQL = `
INSERT INTO vehicle_data_source
  (protocol, source_ip, latest_source_endpoint, platform_name, source_code, source_kind, first_seen_at, latest_seen_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
  latest_source_endpoint = VALUES(latest_source_endpoint),
  platform_name = CASE
    WHEN vehicle_data_source.platform_name IS NULL OR TRIM(vehicle_data_source.platform_name) = ''
      THEN VALUES(platform_name)
    ELSE vehicle_data_source.platform_name
  END,
  source_code = CASE
    WHEN vehicle_data_source.source_code IS NULL OR TRIM(vehicle_data_source.source_code) = ''
      THEN VALUES(source_code)
    ELSE vehicle_data_source.source_code
  END,
  source_kind = CASE
    WHEN vehicle_data_source.source_kind IS NULL OR TRIM(vehicle_data_source.source_kind) = '' OR vehicle_data_source.source_kind = 'UNKNOWN'
      THEN VALUES(source_kind)
    ELSE vehicle_data_source.source_kind
  END,
  enabled = CASE
    WHEN vehicle_data_source.enabled = 0
      AND (vehicle_data_source.remark LIKE 'auto-retired:%' OR vehicle_data_source.remark = 'auto-reenabled: source evidence restored')
      AND (
        (VALUES(platform_name) IS NOT NULL AND TRIM(VALUES(platform_name)) <> '')
        OR (VALUES(source_code) IS NOT NULL AND TRIM(VALUES(source_code)) <> '')
        OR VALUES(source_kind) <> 'UNKNOWN'
      )
      THEN 1
    ELSE vehicle_data_source.enabled
  END,
  remark = CASE
    WHEN vehicle_data_source.enabled = 0
      AND (vehicle_data_source.remark LIKE 'auto-retired:%' OR vehicle_data_source.remark = 'auto-reenabled: source evidence restored')
      AND (
        (VALUES(platform_name) IS NOT NULL AND TRIM(VALUES(platform_name)) <> '')
        OR (VALUES(source_code) IS NOT NULL AND TRIM(VALUES(source_code)) <> '')
        OR VALUES(source_kind) <> 'UNKNOWN'
      )
      THEN 'auto-reenabled: source evidence restored'
    ELSE vehicle_data_source.remark
  END,
  latest_seen_at = GREATEST(COALESCE(latest_seen_at, VALUES(latest_seen_at)), VALUES(latest_seen_at)),
  updated_at = CURRENT_TIMESTAMP
`
