package dialectsfcrm

import (
	"context"
	"encoding/json"
	"errors"
	"log"
	"net/http"
	"regexp"
	"strconv"
	"strings"

	"github.com/nexuscrm/dialect-sf-crm/wire"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/contract"
	"github.com/nexuscrm/shared/pkg/dialect"
	sharederrors "github.com/nexuscrm/shared/pkg/errors"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/nexuscrm/shared/pkg/queryspec"
)

const (
	reportGenericInternalErrorMessage = "An internal server error occurred. Contact your system administrator."
	reportDeveloperNameMaxBytes       = 80
)

var (
	reportNonDeveloperNameChars = regexp.MustCompile(`[^a-zA-Z0-9_]`)
	reportRepeatedUnderscores   = regexp.MustCompile(`_+`)
)

type reportResponse struct {
	ID            string `json:"id"`
	Name          string `json:"name"`
	DeveloperName string `json:"developerName"`
	FolderID      string `json:"folderId,omitempty"`
	Description   string `json:"description,omitempty"`
	ReportType    string `json:"reportType,omitempty"`
	SourceObject  string `json:"sourceObject,omitempty"`
}

type reportFilterStorageWire struct {
	Column   string `json:"column"`
	Operator string `json:"operator"`
	Value    string `json:"value"`
}

type reportStandardDateFilterStorageWire struct {
	Column        string `json:"column"`
	DurationValue string `json:"durationValue"`
	StartDate     string `json:"startDate"`
	EndDate       string `json:"endDate"`
}

func ListReportsNeutralHandler(ctx context.Context, req *dialect.Request, deps dialect.Deps) (*dialect.Response, error) {
	query := deps.Contracts.Query
	if query == nil {
		return reportInternalErrorResponseWithLog("query contract unavailable", nil), nil
	}
	limit := 200
	if raw := queryValue(req, "limit"); raw != "" {
		if parsed, err := strconv.Atoi(raw); err == nil && parsed > 0 && parsed <= 2000 {
			limit = parsed
		}
	}
	result, err := query.Query(ctx, queryspec.QuerySpec{
		ObjectAPIName: constants.TableReport,
		SortField:     "Name",
		SortDirection: "ASC",
		Limit:         limit,
	}, req.User)
	if err != nil {
		return reportServiceErrorResponse(req, "list reports", err), nil
	}
	records := []contract.Record(nil)
	if result != nil {
		records = result.Records
	}
	reports := make([]reportResponse, 0, len(records))
	for _, record := range records {
		reports = append(reports, reportResponseFromRecord(record))
	}
	return &dialect.Response{Status: http.StatusOK, Body: map[string]interface{}{
		"reports":   reports,
		"totalSize": len(reports),
	}}, nil
}

func RunReportNeutralHandler(ctx context.Context, req *dialect.Request, deps dialect.Deps) (*dialect.Response, error) {
	reports := deps.Contracts.Reports
	if reports == nil {
		return reportInternalErrorResponseWithLog("reports contract unavailable", nil), nil
	}
	reportID, resp := reportIDParam(req)
	if resp != nil {
		return resp, nil
	}
	def, err := reports.GetReportMetadata(ctx, reportID, req.User)
	if err != nil {
		return reportServiceErrorResponse(req, "get report metadata", err), nil
	}
	result, err := reports.RunReportDefinition(ctx, def, req.User, nil, 0)
	if err != nil {
		return reportServiceErrorResponse(req, "run report", err), nil
	}
	schema := reportSchema(ctx, deps, resultSourceObject(result))
	return &dialect.Response{Status: http.StatusOK, Body: NewReportWireAdapter().ProjectReportResult(result, schema)}, nil
}

func RunReportExecutionNeutralHandler(ctx context.Context, req *dialect.Request, deps dialect.Deps) (*dialect.Response, error) {
	reports := deps.Contracts.Reports
	if reports == nil {
		return reportInternalErrorResponseWithLog("reports contract unavailable", nil), nil
	}
	execReq, err := NewReportRequestAdapter().ParseReportExecutionRequest(req.Body)
	if err != nil {
		return &dialect.Response{Status: http.StatusBadRequest, Body: wire.SFErrorResponse(wire.SFCodeInvalidField, err.Error())}, nil
	}
	if execReq.ReportID == "" && execReq.Definition == nil {
		return &dialect.Response{Status: http.StatusBadRequest, Body: wire.SFErrorResponse(wire.SFCodeRequiredFieldMissing, missingReportExecutionTargetMessage(execReq))}, nil
	}

	var def *models.ReportDefinition
	if execReq.ReportID != "" {
		var err error
		def, err = reports.GetReportMetadata(ctx, execReq.ReportID, req.User)
		if err != nil {
			return reportServiceErrorResponse(req, "get report metadata", err), nil
		}
	} else {
		def = &models.ReportDefinition{}
	}
	if execReq.Definition != nil {
		if resp := normalizeReportDefinitionRequestSourcesResponse(ctx, req, deps, execReq.Definition); resp != nil {
			return resp, nil
		}
		applyReportDefinitionRequest(def, *execReq.Definition)
	}
	if def.SourceObject == "" {
		message := "sourceObject is required"
		if execReq.Definition != nil {
			message = missingReportDefinitionSourceObjectMessage(*execReq.Definition)
		}
		return &dialect.Response{Status: http.StatusBadRequest, Body: wire.SFErrorResponse(wire.SFCodeRequiredFieldMissing, message)}, nil
	}
	defaultReportDisplayMode(def)

	result, err := reports.RunReportDefinition(ctx, def, req.User, nil, execReq.Limit)
	if err != nil {
		return reportServiceErrorResponse(req, "execute report", err), nil
	}
	schema := reportSchema(ctx, deps, resultSourceObject(result))
	return &dialect.Response{Status: http.StatusOK, Body: NewReportWireAdapter().ProjectReportResult(result, schema)}, nil
}

func DescribeReportNeutralHandler(ctx context.Context, req *dialect.Request, deps dialect.Deps) (*dialect.Response, error) {
	reports := deps.Contracts.Reports
	if reports == nil {
		return reportInternalErrorResponseWithLog("reports contract unavailable", nil), nil
	}
	reportID, resp := reportIDParam(req)
	if resp != nil {
		return resp, nil
	}
	def, err := reports.GetReportMetadata(ctx, reportID, req.User)
	if err != nil {
		return reportServiceErrorResponse(req, "describe report", err), nil
	}
	schema := reportSchema(ctx, deps, def.SourceObject)
	return &dialect.Response{Status: http.StatusOK, Body: NewReportWireAdapter().ProjectReportDescribeResponse(def, schema)}, nil
}

func ExecuteReportDefinitionNeutralHandler(ctx context.Context, req *dialect.Request, deps dialect.Deps) (*dialect.Response, error) {
	reports := deps.Contracts.Reports
	if reports == nil {
		return reportInternalErrorResponseWithLog("reports contract unavailable", nil), nil
	}
	defReq, err := NewReportRequestAdapter().ParseReportDefinitionRequest(req.Body)
	if err != nil {
		return &dialect.Response{Status: http.StatusBadRequest, Body: wire.SFErrorResponse(wire.SFCodeRequiredFieldMissing, err.Error())}, nil
	}
	def := &defReq.Definition
	if def.Name == "" {
		return &dialect.Response{Status: http.StatusBadRequest, Body: wire.SFErrorResponse(wire.SFCodeRequiredFieldMissing, missingReportDefinitionNameMessage(defReq))}, nil
	}
	if resp := normalizeReportDefinitionRequestSourcesResponse(ctx, req, deps, &defReq); resp != nil {
		return resp, nil
	}
	if def.SourceObject == "" {
		return &dialect.Response{Status: http.StatusBadRequest, Body: wire.SFErrorResponse(wire.SFCodeRequiredFieldMissing, missingReportDefinitionSourceObjectMessage(defReq))}, nil
	}
	defaultReportDisplayMode(def)

	result, err := reports.RunReportDefinition(ctx, def, req.User, nil, 0)
	if err != nil {
		return reportServiceErrorResponse(req, "execute report definition", err), nil
	}
	schema := reportSchema(ctx, deps, resultSourceObject(result))
	return &dialect.Response{Status: http.StatusOK, Body: NewReportWireAdapter().ProjectReportResult(result, schema)}, nil
}

func CreateReportNeutralHandler(ctx context.Context, req *dialect.Request, deps dialect.Deps) (*dialect.Response, error) {
	records := deps.Contracts.Records
	if records == nil {
		return reportInternalErrorResponseWithLog("records contract unavailable", nil), nil
	}
	defReq, err := NewReportRequestAdapter().ParseReportDefinitionRequest(req.Body)
	if err != nil {
		return &dialect.Response{Status: http.StatusBadRequest, Body: wire.SFErrorResponse(wire.SFCodeRequiredFieldMissing, err.Error())}, nil
	}
	if defReq.Definition.Name == "" {
		return &dialect.Response{Status: http.StatusBadRequest, Body: wire.SFErrorResponse(wire.SFCodeRequiredFieldMissing, missingReportDefinitionNameMessage(defReq))}, nil
	}
	if resp := normalizeReportDefinitionRequestSourcesResponse(ctx, req, deps, &defReq); resp != nil {
		return resp, nil
	}
	if defReq.Definition.SourceObject == "" {
		return &dialect.Response{Status: http.StatusBadRequest, Body: wire.SFErrorResponse(wire.SFCodeRequiredFieldMissing, missingReportDefinitionSourceObjectMessage(defReq))}, nil
	}

	data := reportDefinitionRequestRecord(defReq, true)
	if defReq.Fields.FolderID && defReq.FolderID != "" {
		if resp := reportManageFolderAccessResponse(ctx, req, deps, defReq.FolderID); resp != nil {
			return resp, nil
		}
		data["FolderId"] = defReq.FolderID
	}

	created, err := records.Insert(ctx, constants.TableReport, data, req.User)
	if err != nil {
		return reportWriteErrorResponse(req, "create report", err, wire.SFCodeInsertFailed), nil
	}
	return &dialect.Response{Status: http.StatusCreated, Body: map[string]any{"id": reportRecordString(created, "Id")}}, nil
}

func UpdateReportNeutralHandler(ctx context.Context, req *dialect.Request, deps dialect.Deps) (*dialect.Response, error) {
	records := deps.Contracts.Records
	if records == nil {
		return reportInternalErrorResponseWithLog("records contract unavailable", nil), nil
	}
	reportID, resp := reportIDParam(req)
	if resp != nil {
		return resp, nil
	}
	defReq, err := NewReportRequestAdapter().ParseReportDefinitionRequest(req.Body)
	if err != nil {
		return &dialect.Response{Status: http.StatusBadRequest, Body: wire.SFErrorResponse(wire.SFCodeInvalidField, err.Error())}, nil
	}
	if resp := normalizeReportDefinitionRequestSourcesResponse(ctx, req, deps, &defReq); resp != nil {
		return resp, nil
	}
	updates := reportDefinitionRequestRecord(defReq, false)
	if defReq.Fields.FolderID && defReq.FolderID != "" {
		if resp := reportManageFolderAccessResponse(ctx, req, deps, defReq.FolderID); resp != nil {
			return resp, nil
		}
		updates["FolderId"] = defReq.FolderID
	}
	if len(updates) == 0 {
		return &dialect.Response{Status: http.StatusBadRequest, Body: wire.SFErrorResponse(wire.SFCodeInvalidField, "No fields to update")}, nil
	}

	if err := records.Update(ctx, constants.TableReport, reportID, updates, req.User); err != nil {
		return reportWriteErrorResponse(req, "update report", err, wire.SFCodeUpdateFailed), nil
	}
	record, err := records.Retrieve(ctx, constants.TableReport, reportID, req.User)
	if err != nil {
		return reportRecordRetrieveErrorResponse(req, err), nil
	}
	return &dialect.Response{Status: http.StatusOK, Body: reportResponseFromRecord(record)}, nil
}

func DeleteReportNeutralHandler(ctx context.Context, req *dialect.Request, deps dialect.Deps) (*dialect.Response, error) {
	records := deps.Contracts.Records
	if records == nil {
		return reportInternalErrorResponseWithLog("records contract unavailable", nil), nil
	}
	reportID, resp := reportIDParam(req)
	if resp != nil {
		return resp, nil
	}
	if err := records.Delete(ctx, constants.TableReport, reportID, req.User); err != nil {
		return reportWriteErrorResponse(req, "delete report", err, wire.SFCodeDeleteFailed), nil
	}
	return &dialect.Response{Status: http.StatusNoContent}, nil
}

func applyReportDefinitionRequest(def *models.ReportDefinition, req reportDefinitionRequest) {
	if def == nil {
		return
	}
	src := req.Definition
	if req.Fields.Name {
		def.Name = src.Name
	}
	if req.Fields.SourceObject || req.Fields.SourceRef || req.Fields.ReportType {
		sourceObject, sourceRef := reportDefinitionRequestSourcePair(req)
		if sourceObject != "" || req.Fields.SourceObject {
			def.SourceObject = sourceObject
		}
		if sourceRef != "" || req.Fields.SourceObject || req.Fields.SourceRef || req.Fields.ReportType {
			def.SourceRef = sourceRef
		}
	}
	if req.Fields.DisplayMode {
		def.DisplayMode = src.EffectiveDisplayMode()
	}
	if req.Fields.Scope {
		def.Scope = src.Scope
	}
	if req.Fields.Columns {
		def.Columns = append([]string(nil), src.Columns...)
	}
	if req.Fields.Filters {
		def.Filters = append([]models.ReportFilter(nil), src.Filters...)
	}
	if req.Fields.Grouping {
		def.Grouping = append([]string(nil), src.Grouping...)
	}
	if req.Fields.DateFilter {
		def.DateFilter = cloneStandardDateFilter(src.DateFilter)
	}
	def.NormalizeBoundaryAliases()
}

func defaultReportDisplayMode(def *models.ReportDefinition) {
	if def == nil || def.EffectiveDisplayMode() != "" {
		return
	}
	if len(def.Grouping) > 0 {
		def.DisplayMode = "SUMMARY"
		def.NormalizeBoundaryAliases()
		return
	}
	def.DisplayMode = "TABULAR"
	def.NormalizeBoundaryAliases()
}

func reportDefinitionRequestRecord(req reportDefinitionRequest, includeIdentity bool) contract.Record {
	def := req.Definition
	data := contract.Record{}
	if includeIdentity || (req.Fields.Name && def.Name != "") {
		data["Name"] = def.Name
	}
	if includeIdentity {
		developerName := req.DeveloperName
		if developerName == "" {
			developerName = sanitizeReportDeveloperName(def.Name)
		}
		data["DeveloperName"] = developerName
	} else if req.Fields.DeveloperName && req.DeveloperName != "" {
		data["DeveloperName"] = req.DeveloperName
	}
	if includeIdentity || req.Fields.SourceObject || req.Fields.SourceRef || req.Fields.ReportType {
		sourceObject, sourceRef := reportDefinitionRequestSourcePair(req)
		if sourceObject != "" {
			data["SourceObject"] = sourceObject
		}
		if sourceRef != "" {
			data["SourceRef"] = sourceRef
			data["ReportType"] = sourceRef
		}
	}
	if displayMode := def.EffectiveDisplayMode(); displayMode != "" && (includeIdentity || req.Fields.DisplayMode) {
		data["DisplayMode"] = displayMode
	}
	if req.Fields.Description && req.Description != "" {
		data["Description"] = req.Description
	}
	if req.Fields.Scope && def.Scope != "" {
		data["Scope"] = def.Scope
	}
	if req.Fields.Columns && len(def.Columns) > 0 {
		if b, err := json.Marshal(def.Columns); err == nil {
			data["Columns"] = string(b)
		}
	}
	if req.Fields.Filters && len(def.Filters) > 0 {
		if b, err := json.Marshal(reportFiltersStorageFromModel(def.Filters)); err == nil {
			data["Filters"] = string(b)
		}
	}
	if req.Fields.Grouping && len(def.Grouping) > 0 {
		if b, err := json.Marshal(def.Grouping); err == nil {
			data["Grouping"] = string(b)
		}
	}
	if req.Fields.DateFilter && def.DateFilter != nil {
		if b, err := json.Marshal(reportStandardDateFilterStorageFromModel(def.DateFilter)); err == nil {
			data["StandardDateFilter"] = string(b)
		}
	}
	return data
}

func reportDefinitionRequestSourcePair(req reportDefinitionRequest) (string, string) {
	sourceObject := req.Definition.SourceObject
	sourceRef := req.Definition.EffectiveSourceRef()
	if sourceRef == "" {
		sourceRef = sourceObject
	}
	return sourceObject, sourceRef
}

func normalizeReportDefinitionRequestSourcesResponse(ctx context.Context, req *dialect.Request, deps dialect.Deps, defReq *reportDefinitionRequest) *dialect.Response {
	message, err := normalizeReportDefinitionRequestSources(ctx, req, deps, defReq)
	if err != nil {
		return reportInternalErrorResponseWithLog("report source normalization failed", err)
	}
	if message != "" {
		return &dialect.Response{Status: http.StatusBadRequest, Body: wire.SFErrorResponse(wire.SFCodeInvalidField, message)}
	}
	return nil
}

func normalizeReportDefinitionRequestSources(ctx context.Context, req *dialect.Request, deps dialect.Deps, defReq *reportDefinitionRequest) (string, error) {
	if defReq == nil {
		return "", nil
	}
	sourceObjectTouched := defReq.Fields.SourceObject
	sourceRefTouched := defReq.Fields.SourceRef || defReq.Fields.ReportType
	if !sourceObjectTouched && !sourceRefTouched {
		return "", nil
	}
	sourceObject, sourceRef := reportDefinitionRequestSourcePair(*defReq)
	if sourceObjectTouched && sourceRef != "" && strings.EqualFold(sourceObject, sourceRef) {
		resolved, err := resolveReportSourceBaseObject(ctx, req, deps, sourceRef)
		if err != nil {
			return "", err
		}
		if resolved != "" && !strings.EqualFold(resolved, sourceRef) {
			defReq.Definition.SourceObject = resolved
			defReq.Definition.SourceRef = sourceRef
			defReq.Fields.SourceRef = true
			defReq.Fields.ReportType = true
		}
		return "", nil
	}
	if sourceRefTouched && !sourceObjectTouched {
		resolved, err := resolveReportSourceBaseObject(ctx, req, deps, sourceRef)
		if err != nil {
			return "", err
		}
		if sourceRef == "" || resolved == "" || strings.EqualFold(resolved, sourceRef) {
			return "sourceRef/reportType requires sourceObject or a resolvable report source", nil
		}
		defReq.Definition.SourceObject = resolved
		defReq.Fields.SourceObject = true
		return "", nil
	}
	if sourceObject == "" || sourceRef == "" {
		return "", nil
	}
	matches, err := reportSourceRefMatchesSourceObject(ctx, req, deps, sourceRef, sourceObject)
	if err != nil {
		return "", err
	}
	if matches {
		return "", nil
	}
	return "sourceObject and sourceRef/reportType refer to different report sources", nil
}

func reportSourceRefMatchesSourceObject(ctx context.Context, req *dialect.Request, deps dialect.Deps, sourceRef, sourceObject string) (bool, error) {
	if isSingleObjectReportSourceRef(sourceRef, sourceObject) {
		return true, nil
	}
	resolved, err := resolveReportSourceBaseObject(ctx, req, deps, sourceRef)
	if err != nil {
		return false, err
	}
	if resolved != "" && !strings.EqualFold(resolved, sourceRef) {
		return strings.EqualFold(resolved, sourceObject), nil
	}
	return strings.EqualFold(resolved, sourceObject), nil
}

func isSingleObjectReportSourceRef(sourceRef, sourceObject string) bool {
	sourceRef = strings.TrimSpace(sourceRef)
	sourceObject = strings.TrimSpace(sourceObject)
	return sourceRef != "" && sourceObject != "" && strings.EqualFold(sourceRef, sourceObject+"List")
}

func resolveReportSourceBaseObject(ctx context.Context, req *dialect.Request, deps dialect.Deps, sourceRef string) (string, error) {
	sourceRef = strings.TrimSpace(sourceRef)
	if sourceRef == "" {
		return "", nil
	}
	if resolver, ok := deps.Contracts.Reports.(interface {
		ResolveReportSourceBaseObject(context.Context, string, *models.UserSession) (string, error)
	}); ok && resolver != nil {
		resolved, err := resolver.ResolveReportSourceBaseObject(ctx, sourceRef, req.User)
		return strings.TrimSpace(resolved), err
	}
	resolved := NewReportDefinitionDialect().ResolveSourceObject(sourceRef, nil)
	return strings.TrimSpace(resolved), nil
}

func missingReportDefinitionNameMessage(req reportDefinitionRequest) string {
	if req.Messages.MissingName != "" {
		return req.Messages.MissingName
	}
	return "name is required"
}

func missingReportDefinitionSourceObjectMessage(req reportDefinitionRequest) string {
	if req.Definition.EffectiveSourceRef() == "" && req.Messages.MissingReportTypeOrSourceObject != "" {
		return req.Messages.MissingReportTypeOrSourceObject
	}
	if req.Messages.MissingSourceObject != "" {
		return req.Messages.MissingSourceObject
	}
	return "sourceObject is required"
}

func missingReportExecutionTargetMessage(req reportExecutionRequest) string {
	if req.Messages.MissingReportIDOrDefinition != "" {
		return req.Messages.MissingReportIDOrDefinition
	}
	return "reportId or reportDefinition is required"
}

func reportResponseFromRecord(record contract.Record) reportResponse {
	reportType := reportRecordString(record, "ReportType")
	if reportType == "" {
		reportType = reportRecordString(record, "SourceRef")
	}
	return reportResponse{
		ID:            reportRecordString(record, "Id"),
		Name:          reportRecordString(record, "Name"),
		DeveloperName: reportRecordString(record, "DeveloperName"),
		FolderID:      reportRecordString(record, "FolderId"),
		Description:   reportRecordString(record, "Description"),
		ReportType:    reportType,
		SourceObject:  reportRecordString(record, "SourceObject"),
	}
}

func reportFiltersStorageFromModel(in []models.ReportFilter) []reportFilterStorageWire {
	if in == nil {
		return nil
	}
	out := make([]reportFilterStorageWire, len(in))
	for i, f := range in {
		out[i] = reportFilterStorageWire{Column: f.Column, Operator: f.Operator, Value: f.Value}
	}
	return out
}

func reportStandardDateFilterStorageFromModel(in *models.ReportDateFilter) *reportStandardDateFilterStorageWire {
	if in == nil {
		return nil
	}
	return &reportStandardDateFilterStorageWire{
		Column:        in.Column,
		DurationValue: in.DurationValue,
		StartDate:     in.StartDate,
		EndDate:       in.EndDate,
	}
}

func cloneStandardDateFilter(in *models.ReportDateFilter) *models.ReportDateFilter {
	if in == nil {
		return nil
	}
	out := *in
	return &out
}

func reportIDParam(req *dialect.Request) (string, *dialect.Response) {
	id := strings.TrimSpace(req.Params["reportId"])
	if id == "" {
		return "", &dialect.Response{Status: http.StatusBadRequest, Body: wire.SFErrorResponse(wire.SFCodeInvalidRequest, "reportId is required")}
	}
	return id, nil
}

func reportSchema(ctx context.Context, deps dialect.Deps, sourceObject string) *models.ObjectMetadata {
	if deps.Contracts.Metadata == nil || sourceObject == "" {
		return nil
	}
	schema, err := deps.Contracts.Metadata.Describe(ctx, sourceObject)
	if err != nil {
		return nil
	}
	return schema
}

func resultSourceObject(result *models.ReportResult) string {
	if result == nil {
		return ""
	}
	return result.ReportMetadata.SourceObject
}

func reportManageFolderAccessResponse(ctx context.Context, req *dialect.Request, deps dialect.Deps, folderID string) *dialect.Response {
	folderAccess := deps.Contracts.FolderAccess
	if folderAccess == nil {
		return reportInternalErrorResponseWithLog("folder access contract unavailable for report folder assignment", nil)
	}
	if !folderAccess.CheckFolderAccess(ctx, req.User, folderID, contract.FolderAccessManage) {
		return forbiddenResponse("You do not have Manage access on the target folder")
	}
	return nil
}

func reportServiceErrorResponse(req *dialect.Request, operation string, err error) *dialect.Response {
	if resp := respondServiceError(req, err); resp != nil {
		if resp.Status >= http.StatusInternalServerError {
			logReportInternalError(operation, err)
		}
		return resp
	}
	if resp := reportServiceBadRequestResponse(err); resp != nil {
		return resp
	}
	return reportInternalErrorResponseWithLog(operation, err)
}

func reportRecordRetrieveErrorResponse(req *dialect.Request, err error) *dialect.Response {
	if resp := respondServiceError(req, err); resp != nil {
		if resp.Status >= http.StatusInternalServerError {
			logReportInternalError("retrieve updated report", err)
		}
		return resp
	}
	return reportInternalErrorResponseWithLog("retrieve updated report", err)
}

func reportServiceBadRequestResponse(err error) *dialect.Response {
	if resp := validationErrorMaybe(err, wire.SFCodeInvalidRequest); resp != nil {
		return resp
	}
	var statusErr httpStatusError
	if errors.As(err, &statusErr) && statusErr.HTTPStatus() == http.StatusBadRequest {
		return queryErrorResponse(http.StatusBadRequest, wire.SFCodeInvalidRequest, err.Error())
	}
	return nil
}

func reportWriteErrorResponse(req *dialect.Request, operation string, err error, fallbackCode string) *dialect.Response {
	if err == nil {
		return nil
	}
	if resp := respondServiceError(req, err); resp != nil {
		if resp.Status >= http.StatusInternalServerError {
			logReportInternalError(operation, err)
		}
		return resp
	}
	if fields, message, ok := sharederrors.FieldWriteDeniedDetails(err); ok {
		return &dialect.Response{
			Status: http.StatusBadRequest,
			Body:   wire.SFErrorWithFields(wire.SFCodeInvalidFieldForInsertUpdate, message, fields...),
		}
	}
	if message, ok := sharederrors.ValidationRuleMessage(err); ok {
		return &dialect.Response{
			Status: http.StatusBadRequest,
			Body:   wire.SFErrorResponse(wire.SFCodeFieldCustomValidationException, message),
		}
	}
	if resp := validationErrorMaybe(err, fallbackCode); resp != nil {
		return resp
	}
	if sfErr, status, ok := wire.SFErrorFromDomainForVersion(err, apiVersionOrDefault(req.Version)); ok {
		if status >= http.StatusInternalServerError {
			logReportInternalError(operation, err)
		}
		return &dialect.Response{Status: status, Body: []wire.SFError{sfErr}}
	}
	return reportInternalErrorResponseWithLog(operation, err)
}

func reportInternalErrorResponse() *dialect.Response {
	return internalErrorResponse(reportGenericInternalErrorMessage)
}

func reportInternalErrorResponseWithLog(operation string, err error) *dialect.Response {
	logReportInternalError(operation, err)
	return reportInternalErrorResponse()
}

func logReportInternalError(operation string, err error) {
	if err == nil {
		log.Printf("reports: %s", operation)
		return
	}
	if cause := errors.Unwrap(err); cause != nil {
		log.Printf("reports: %s: %v: %v", operation, err, cause)
		return
	}
	log.Printf("reports: %s: %v", operation, err)
}

func sanitizeReportDeveloperName(name string) string {
	if name == "" {
		return ""
	}
	clean := strings.ReplaceAll(name, " ", "_")
	clean = reportNonDeveloperNameChars.ReplaceAllString(clean, "")
	clean = reportRepeatedUnderscores.ReplaceAllString(clean, "_")
	clean = strings.Trim(clean, "_")
	if len(clean) > 0 && clean[0] >= '0' && clean[0] <= '9' {
		clean = "X" + clean
	}
	if clean == "" {
		clean = "Unnamed"
	}
	if len(clean) > reportDeveloperNameMaxBytes {
		clean = strings.TrimSuffix(clean[:reportDeveloperNameMaxBytes], "_")
	}
	return clean
}
