package service

import (
	"context"
	"net/http"
	"strings"

	"wucher/internal/domain/user"
)

type UserWriteError struct {
	Status  int
	Title   string
	Detail  string
	Pointer string
}

func (e *UserWriteError) Error() string {
	if e == nil {
		return ""
	}
	return e.Detail
}

type UserWriteResult struct {
	Row                         *user.User
	PreviousProfileAttachmentID []byte
}

type UserCreateInput struct {
	ID                  []byte
	Email               string
	Username            string
	FirstName           string
	LastName            string
	MobilePhone         string
	Timezone            string
	RoleID              []byte
	RoleIDs             [][]byte
	ProfileAttachmentID []byte
	CreatedBy           []byte
	UpdatedBy           []byte
}

type UserUpdateInput struct {
	ID                   []byte
	Email                *string
	FirstName            *string
	LastName             *string
	MobilePhone          *string
	Timezone             *string
	ProfileAttachmentSet bool
	ProfileAttachmentID  []byte
	ActorUserID          []byte
}

func (s *UserService) CreateDetailed(ctx context.Context, in UserCreateInput) (*UserWriteResult, error) {
	if s == nil || s.repo == nil {
		return nil, &UserWriteError{Status: http.StatusInternalServerError, Title: "Create failed", Detail: "user service is not configured"}
	}
	email := strings.TrimSpace(in.Email)
	username := strings.TrimSpace(in.Username)
	firstName := strings.TrimSpace(in.FirstName)
	lastName := strings.TrimSpace(in.LastName)
	if email == "" || username == "" || firstName == "" || lastName == "" {
		return nil, &UserWriteError{Status: http.StatusUnprocessableEntity, Title: "Validation error", Detail: "email, username, first_name, and last_name are required", Pointer: "/data/attributes"}
	}
	row := &user.User{
		ID:                  append([]byte(nil), in.ID...),
		Email:               email,
		Username:            username,
		FirstName:           firstName,
		LastName:            lastName,
		MobilePhone:         strings.TrimSpace(in.MobilePhone),
		Timezone:            strings.TrimSpace(in.Timezone),
		RoleID:              append([]byte(nil), in.RoleID...),
		RoleIDs:             appendUniqueIDs(in.RoleIDs),
		ProfileAttachmentID: append([]byte(nil), in.ProfileAttachmentID...),
		ImageAttachmentID:   append([]byte(nil), in.ProfileAttachmentID...),
		CreatedBy:           append([]byte(nil), in.CreatedBy...),
		UpdatedBy:           append([]byte(nil), in.UpdatedBy...),
	}
	if err := s.Create(ctx, row); err != nil {
		return nil, &UserWriteError{Status: http.StatusBadRequest, Title: "Create failed", Detail: err.Error()}
	}
	created, err := s.GetByID(ctx, row.ID)
	if err != nil {
		return nil, &UserWriteError{Status: http.StatusBadRequest, Title: "Create failed", Detail: err.Error()}
	}
	if created == nil {
		created = row
	}
	return &UserWriteResult{Row: created}, nil
}

func (s *UserService) UpdateDetailed(ctx context.Context, in UserUpdateInput) (*UserWriteResult, error) {
	if s == nil || s.repo == nil {
		return nil, &UserWriteError{Status: http.StatusInternalServerError, Title: "Update failed", Detail: "user service is not configured"}
	}
	if len(in.ID) != 16 {
		return nil, &UserWriteError{Status: http.StatusUnprocessableEntity, Title: "Validation error", Detail: "uuid is invalid UUID", Pointer: "/path/uuid"}
	}

	existing, err := s.GetByID(ctx, in.ID)
	if err != nil || existing == nil {
		return nil, &UserWriteError{Status: http.StatusNotFound, Title: "Not found", Detail: "user not found"}
	}
	prevProfileAttachmentID := append([]byte(nil), existing.ProfileAttachmentID...)

	if in.Email != nil {
		email := strings.TrimSpace(*in.Email)
		if email == "" {
			return nil, &UserWriteError{Status: http.StatusUnprocessableEntity, Title: "Validation error", Detail: "email cannot be empty", Pointer: "/data/attributes/email"}
		}
		existing.Email = email
	}
	if in.FirstName != nil {
		firstName := strings.TrimSpace(*in.FirstName)
		if firstName == "" {
			return nil, &UserWriteError{Status: http.StatusUnprocessableEntity, Title: "Validation error", Detail: "first_name cannot be empty", Pointer: "/data/attributes/first_name"}
		}
		existing.FirstName = firstName
	}
	if in.LastName != nil {
		lastName := strings.TrimSpace(*in.LastName)
		if lastName == "" {
			return nil, &UserWriteError{Status: http.StatusUnprocessableEntity, Title: "Validation error", Detail: "last_name cannot be empty", Pointer: "/data/attributes/last_name"}
		}
		existing.LastName = lastName
	}
	if in.MobilePhone != nil {
		existing.MobilePhone = strings.TrimSpace(*in.MobilePhone)
	}
	if in.Timezone != nil {
		existing.Timezone = strings.TrimSpace(*in.Timezone)
	}
	if in.ProfileAttachmentSet {
		if len(in.ProfileAttachmentID) == 0 {
			existing.ProfileAttachmentID = nil
			existing.ImageAttachmentID = nil
		} else {
			existing.ProfileAttachmentID = append([]byte(nil), in.ProfileAttachmentID...)
			existing.ImageAttachmentID = append([]byte(nil), in.ProfileAttachmentID...)
		}
		existing.ProfileAttachmentPatchSet = true
	}
	existing.UpdatedBy = append([]byte(nil), in.ActorUserID...)

	if err := s.Update(ctx, existing); err != nil {
		return nil, &UserWriteError{Status: http.StatusBadRequest, Title: "Update failed", Detail: err.Error()}
	}
	updated, err := s.GetByID(ctx, existing.ID)
	if err != nil {
		return nil, &UserWriteError{Status: http.StatusBadRequest, Title: "Update failed", Detail: err.Error()}
	}
	if updated == nil {
		updated = existing
	}
	return &UserWriteResult{Row: updated, PreviousProfileAttachmentID: prevProfileAttachmentID}, nil
}
