package platform

import (
	"context"
	"fmt"
	"net/url"
	"regexp"
	"strings"
	"time"
)

var vehicleOperationStatuses = map[string]bool{
	"unknown": true, "active": true, "inactive": true, "maintenance": true, "retired": true,
}

const (
	vehicleProfileSyncLimit            = 500
	profileSyncCreated                 = "created"
	profileSyncUpdated                 = "updated"
	profileSyncUnchanged               = "unchanged"
	profileSyncConflictSource          = "conflict_source"
	profileSyncConflictSourceVersion   = "conflict_source_version"
	profileSyncMissingVehicle          = "missing_vehicle"
	profileSyncConflictPolicyPreserve  = "preserve"
	profileSyncConflictPolicyOverwrite = "overwrite"
)

var vehicleProfileSourceSystemPattern = regexp.MustCompile(`^[a-z0-9][a-z0-9._:-]*$`)

func (s *Service) VehicleProfile(ctx context.Context, vin string) (VehicleProfile, error) {
	vin = strings.TrimSpace(vin)
	if err := authorizeVehicleVIN(ctx, vin); err != nil {
		return VehicleProfile{}, err
	}
	if err := validateProfileVIN(vin); err != nil {
		return VehicleProfile{}, err
	}
	store, ok := s.store.(VehicleProfileStore)
	if !ok {
		return decorateVehicleProfile(VehicleProfile{VIN: vin, OperationStatus: "unknown", SourceSystem: "unconfigured", MissingFields: []string{}}), nil
	}
	profile, exists, err := store.VehicleProfile(ctx, vin)
	if err != nil {
		return VehicleProfile{}, err
	}
	if !exists {
		profile = VehicleProfile{VIN: vin, OperationStatus: "unknown", SourceSystem: "unconfigured"}
	}
	return decorateVehicleProfile(profile), nil
}

func (s *Service) SaveVehicleProfile(ctx context.Context, vin string, input VehicleProfileInput) (VehicleProfile, error) {
	vin = strings.TrimSpace(vin)
	if err := validateProfileVIN(vin); err != nil {
		return VehicleProfile{}, err
	}
	store, ok := s.store.(VehicleProfileStore)
	if !ok {
		return VehicleProfile{}, fmt.Errorf("store does not provide durable vehicle profiles")
	}
	exists, err := s.vehicleExists(ctx, vin)
	if err != nil {
		return VehicleProfile{}, err
	}
	if !exists {
		return VehicleProfile{}, clientError{Code: "VEHICLE_NOT_FOUND", Message: "车辆身份不存在，不能创建主档"}
	}
	input = normalizeVehicleProfileInput(input)
	if err := validateVehicleProfileInput(input); err != nil {
		return VehicleProfile{}, err
	}
	profile, err := store.SaveVehicleProfile(ctx, vin, input)
	if err != nil {
		return VehicleProfile{}, err
	}
	return decorateVehicleProfile(profile), nil
}

func (s *Service) SyncVehicleProfiles(ctx context.Context, request VehicleProfileSyncRequest) (VehicleProfileSyncResult, error) {
	store, ok := s.store.(VehicleProfileStore)
	if !ok {
		return VehicleProfileSyncResult{}, fmt.Errorf("store does not provide durable vehicle profiles")
	}
	request = normalizeVehicleProfileSyncRequest(request)
	if err := validateVehicleProfileSyncRequest(request); err != nil {
		return VehicleProfileSyncResult{}, err
	}
	return store.SyncVehicleProfiles(ctx, request)
}

func normalizeVehicleProfileSyncRequest(request VehicleProfileSyncRequest) VehicleProfileSyncRequest {
	request.SourceSystem = strings.ToLower(strings.TrimSpace(request.SourceSystem))
	request.SourceVersion = strings.TrimSpace(request.SourceVersion)
	request.ConflictPolicy = strings.ToLower(strings.TrimSpace(request.ConflictPolicy))
	request.Actor = strings.TrimSpace(request.Actor)
	if request.ConflictPolicy == "" {
		request.ConflictPolicy = profileSyncConflictPolicyPreserve
	}
	for index := range request.Items {
		item := &request.Items[index]
		item.VIN = strings.ToUpper(strings.TrimSpace(item.VIN))
		normalized := normalizeVehicleProfileInput(vehicleProfileSyncInput(*item, request.Actor))
		item.ModelName = normalized.ModelName
		item.VehicleType = normalized.VehicleType
		item.CompanyName = normalized.CompanyName
		item.OperationStatus = normalized.OperationStatus
		item.AccessProvider = normalized.AccessProvider
		item.FirstAccessAt = normalized.FirstAccessAt
		if item.FirstAccessAt != "" {
			if parsed, err := parseVehicleProfileTime(item.FirstAccessAt); err == nil {
				item.FirstAccessAt = parsed.Format(time.RFC3339)
			}
		}
	}
	return request
}

func validateVehicleProfileSyncRequest(request VehicleProfileSyncRequest) error {
	if request.SourceSystem == "" || len(request.SourceSystem) > 64 || !vehicleProfileSourceSystemPattern.MatchString(request.SourceSystem) || request.SourceSystem == "manual" || request.SourceSystem == "unconfigured" {
		return clientError{Code: "VEHICLE_PROFILE_SYNC_SOURCE_INVALID", Message: "sourceSystem 必须是 64 字符内的外部系统标识"}
	}
	if request.SourceVersion == "" || len([]rune(request.SourceVersion)) > 128 {
		return clientError{Code: "VEHICLE_PROFILE_SYNC_VERSION_INVALID", Message: "sourceVersion 不能为空且不能超过 128 个字符"}
	}
	if request.ConflictPolicy != profileSyncConflictPolicyPreserve && request.ConflictPolicy != profileSyncConflictPolicyOverwrite {
		return clientError{Code: "VEHICLE_PROFILE_SYNC_POLICY_INVALID", Message: "conflictPolicy 仅支持 preserve 或 overwrite"}
	}
	if len(request.Items) == 0 || len(request.Items) > vehicleProfileSyncLimit {
		return clientError{Code: "VEHICLE_PROFILE_SYNC_SIZE_INVALID", Message: "单批车辆主档必须为 1 至 500 条"}
	}
	if request.Actor == "" {
		return clientError{Code: "VEHICLE_PROFILE_ACTOR_REQUIRED", Message: "缺少档案同步操作人"}
	}
	seen := make(map[string]struct{}, len(request.Items))
	for _, item := range request.Items {
		if err := validateProfileVIN(item.VIN); err != nil {
			return err
		}
		if _, exists := seen[item.VIN]; exists {
			return clientError{Code: "VEHICLE_PROFILE_SYNC_DUPLICATE_VIN", Message: "同一批次不能包含重复 VIN"}
		}
		seen[item.VIN] = struct{}{}
		if err := validateVehicleProfileInput(vehicleProfileSyncInput(item, request.Actor)); err != nil {
			return err
		}
	}
	return nil
}

func vehicleProfileSyncInput(item VehicleProfileSyncItem, actor string) VehicleProfileInput {
	return VehicleProfileInput{
		ModelName: item.ModelName, VehicleType: item.VehicleType, CompanyName: item.CompanyName,
		OperationStatus: item.OperationStatus, AccessProvider: item.AccessProvider,
		FirstAccessAt: item.FirstAccessAt, RuntimeSeconds: item.RuntimeSeconds, Actor: actor,
	}
}

func vehicleProfileSyncDecision(current VehicleProfile, exists bool, request VehicleProfileSyncRequest, item VehicleProfileSyncItem) string {
	if !exists {
		return profileSyncCreated
	}
	if current.SourceSystem == request.SourceSystem && current.SourceVersion == request.SourceVersion {
		if vehicleProfileSyncFieldsEqual(current, item) {
			return profileSyncUnchanged
		}
		return profileSyncConflictSourceVersion
	}
	if request.ConflictPolicy == profileSyncConflictPolicyPreserve && current.SourceSystem != request.SourceSystem {
		return profileSyncConflictSource
	}
	return profileSyncUpdated
}

func vehicleProfileSyncFieldsEqual(current VehicleProfile, item VehicleProfileSyncItem) bool {
	return current.ModelName == item.ModelName && current.VehicleType == item.VehicleType &&
		current.CompanyName == item.CompanyName && current.OperationStatus == item.OperationStatus &&
		current.AccessProvider == item.AccessProvider && current.FirstAccessAt == item.FirstAccessAt &&
		equalOptionalInt64(current.RuntimeSeconds, item.RuntimeSeconds)
}

func equalOptionalInt64(left, right *int64) bool {
	if left == nil || right == nil {
		return left == nil && right == nil
	}
	return *left == *right
}

func countVehicleProfileSyncResult(result *VehicleProfileSyncResult, status string) {
	switch status {
	case profileSyncCreated:
		result.Created++
	case profileSyncUpdated:
		result.Updated++
	case profileSyncUnchanged:
		result.Unchanged++
	case profileSyncMissingVehicle:
		result.Missing++
	default:
		result.Conflicted++
	}
}

func (s *Service) vehicleExists(ctx context.Context, vin string) (bool, error) {
	page, err := s.store.Vehicles(ctx, url.Values{"keyword": {vin}, "limit": {"20"}})
	if err != nil {
		return false, err
	}
	for _, item := range page.Items {
		if strings.EqualFold(strings.TrimSpace(item.VIN), vin) {
			return true, nil
		}
	}
	return false, nil
}

func validateProfileVIN(vin string) error {
	if vin == "" || len(vin) > 32 {
		return clientError{Code: "VEHICLE_PROFILE_VIN_INVALID", Message: "VIN 不能为空且不能超过 32 个字符"}
	}
	return nil
}

func normalizeVehicleProfileInput(input VehicleProfileInput) VehicleProfileInput {
	input.ModelName = strings.TrimSpace(input.ModelName)
	input.VehicleType = strings.TrimSpace(input.VehicleType)
	input.CompanyName = strings.TrimSpace(input.CompanyName)
	input.OperationStatus = strings.ToLower(strings.TrimSpace(input.OperationStatus))
	input.AccessProvider = strings.TrimSpace(input.AccessProvider)
	input.FirstAccessAt = strings.TrimSpace(input.FirstAccessAt)
	input.Actor = strings.TrimSpace(input.Actor)
	if input.OperationStatus == "" {
		input.OperationStatus = "unknown"
	}
	return input
}

func validateVehicleProfileInput(input VehicleProfileInput) error {
	lengths := []struct {
		value string
		max   int
		name  string
	}{
		{input.ModelName, 128, "车型"}, {input.VehicleType, 64, "车辆类型"},
		{input.CompanyName, 128, "所属企业"}, {input.AccessProvider, 128, "接入服务商"},
	}
	for _, field := range lengths {
		if len([]rune(field.value)) > field.max {
			return clientError{Code: "VEHICLE_PROFILE_FIELD_INVALID", Message: field.name + "长度超出限制"}
		}
	}
	if !vehicleOperationStatuses[input.OperationStatus] {
		return clientError{Code: "VEHICLE_PROFILE_STATUS_INVALID", Message: "运营状态不在允许范围内"}
	}
	if input.RuntimeSeconds != nil && *input.RuntimeSeconds < 0 {
		return clientError{Code: "VEHICLE_PROFILE_RUNTIME_INVALID", Message: "累计运行时长不能为负数"}
	}
	if input.FirstAccessAt != "" {
		if _, err := parseVehicleProfileTime(input.FirstAccessAt); err != nil {
			return clientError{Code: "VEHICLE_PROFILE_TIME_INVALID", Message: "首次接入时间格式无效"}
		}
	}
	if input.Version < 0 {
		return clientError{Code: "VEHICLE_PROFILE_VERSION_INVALID", Message: "档案版本无效"}
	}
	if input.Actor == "" {
		return clientError{Code: "VEHICLE_PROFILE_ACTOR_REQUIRED", Message: "缺少档案维护人"}
	}
	return nil
}

func parseVehicleProfileTime(value string) (time.Time, error) {
	for _, layout := range []string{time.RFC3339, "2006-01-02T15:04", "2006-01-02 15:04:05"} {
		if parsed, err := time.ParseInLocation(layout, value, time.Local); err == nil {
			return parsed, nil
		}
	}
	return time.Time{}, fmt.Errorf("unsupported vehicle profile time")
}

func decorateVehicleProfile(profile VehicleProfile) VehicleProfile {
	missing := make([]string, 0, 7)
	if profile.ModelName == "" {
		missing = append(missing, "modelName")
	}
	if profile.VehicleType == "" {
		missing = append(missing, "vehicleType")
	}
	if profile.CompanyName == "" {
		missing = append(missing, "companyName")
	}
	if profile.OperationStatus == "" || profile.OperationStatus == "unknown" {
		missing = append(missing, "operationStatus")
	}
	if profile.AccessProvider == "" {
		missing = append(missing, "accessProvider")
	}
	if profile.FirstAccessAt == "" {
		missing = append(missing, "firstAccessAt")
	}
	if profile.RuntimeSeconds == nil {
		missing = append(missing, "runtimeSeconds")
	}
	profile.MissingFields = missing
	profile.Completeness = (7 - len(missing)) * 100 / 7
	if profile.OperationStatus == "" {
		profile.OperationStatus = "unknown"
	}
	if profile.SourceSystem == "" {
		profile.SourceSystem = "unconfigured"
	}
	return profile
}
