package user

import (
	"context"
	"net/url"
	"strings"
	"unicode/utf8"

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

const (
	maxReportReasonRunes = 512
	maxReportImages      = 9
	maxReportImageURLLen = 1024
)

var validReportTypes = map[string]struct{}{
	"politics":               {},
	"pornography":            {},
	"graphic_violence":       {},
	"verbal_abuse":           {},
	"fraud":                  {},
	"illegal_content":        {},
	"minors":                 {},
	"in_person_transactions": {},
	"other":                  {},
}

// SubmitReport 校验 App 举报目标和证据 URL，并把不可变举报事实交给 user repository 持久化。
func (s *Service) SubmitReport(ctx context.Context, reporterUserID int64, userID int64, roomID string, reportType string, reason string, imageURLs []string, requestID string) (userdomain.Report, error) {
	if s.userRepository == nil {
		return userdomain.Report{}, xerr.New(xerr.Unavailable, "user repository is not configured")
	}
	reporterUserID, userID, roomID, reportType, reason, imageURLs, targetType, err := normalizeReportInput(reporterUserID, userID, roomID, reportType, reason, imageURLs)
	if err != nil {
		return userdomain.Report{}, err
	}
	nowMs := s.now().UnixMilli()
	report := userdomain.Report{
		ReportID:       idgen.New("rpt"),
		ReporterUserID: reporterUserID,
		TargetType:     targetType,
		UserID:         userID,
		RoomID:         roomID,
		ReportType:     reportType,
		Reason:         reason,
		ImageURLs:      imageURLs,
		Status:         userdomain.ReportStatusSubmitted,
		RequestID:      strings.TrimSpace(requestID),
		CreatedAtMs:    nowMs,
		UpdatedAtMs:    nowMs,
	}

	return s.userRepository.SubmitReport(ctx, report)
}

func normalizeReportInput(reporterUserID int64, userID int64, roomID string, reportType string, reason string, imageURLs []string) (int64, int64, string, string, string, []string, string, error) {
	roomID = strings.TrimSpace(roomID)
	reportType = strings.ToLower(strings.TrimSpace(reportType))
	reason = strings.TrimSpace(reason)
	if reporterUserID <= 0 {
		return 0, 0, "", "", "", nil, "", xerr.New(xerr.InvalidArgument, "reporter_user_id is required")
	}
	hasUser := userID > 0
	hasRoom := roomID != ""
	if hasUser == hasRoom {
		return 0, 0, "", "", "", nil, "", xerr.New(xerr.InvalidArgument, "user_id and room_id must be exactly one")
	}
	if hasUser && userID == reporterUserID {
		return 0, 0, "", "", "", nil, "", xerr.New(xerr.InvalidArgument, "cannot report self")
	}
	targetType := userdomain.ReportTargetUser
	if hasRoom {
		if !roomid.ValidStringID(roomID) {
			return 0, 0, "", "", "", nil, "", xerr.New(xerr.InvalidArgument, "room_id is invalid")
		}
		targetType = userdomain.ReportTargetRoom
	}
	if _, ok := validReportTypes[reportType]; !ok {
		return 0, 0, "", "", "", nil, "", xerr.New(xerr.InvalidArgument, "report_type is invalid")
	}
	if utf8.RuneCountInString(reason) > maxReportReasonRunes {
		return 0, 0, "", "", "", nil, "", xerr.New(xerr.InvalidArgument, "reason is too long")
	}
	normalizedImages, err := normalizeReportImageURLs(imageURLs)
	if err != nil {
		return 0, 0, "", "", "", nil, "", err
	}

	return reporterUserID, userID, roomID, reportType, reason, normalizedImages, targetType, nil
}

func normalizeReportImageURLs(imageURLs []string) ([]string, error) {
	if len(imageURLs) > maxReportImages {
		return nil, xerr.New(xerr.InvalidArgument, "too many report images")
	}
	normalized := make([]string, 0, len(imageURLs))
	for _, raw := range imageURLs {
		value := strings.TrimSpace(raw)
		if value == "" {
			continue
		}
		if len(value) > maxReportImageURLLen {
			return nil, xerr.New(xerr.InvalidArgument, "image url is too long")
		}
		parsed, err := url.Parse(value)
		if err != nil || parsed.Host == "" || (parsed.Scheme != "http" && parsed.Scheme != "https") {
			return nil, xerr.New(xerr.InvalidArgument, "image url is invalid")
		}
		normalized = append(normalized, value)
	}
	return normalized, nil
}
