package requestmodel

import (
	"fmt"
	"net/url"

	"git-molva.ru/Molva/molva-backend/services/api_gateway/internal/constants"
	dbtypes "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/database/types"
)

type SubmissionStatus string

const (
	SubStatusUnspecified SubmissionStatus = "unspecified"
	SubStatusNew         SubmissionStatus = "new"
	SubStatusPending     SubmissionStatus = "pending"
	SubStatusOnInterview SubmissionStatus = "on_interview"
	SubStatusApproved    SubmissionStatus = "approved"
	SubStatusCancelled   SubmissionStatus = "cancelled"
	SubStatusRejected    SubmissionStatus = "rejected"
)

func (s *SubmissionStatus) NullString() *string {
	if s == nil {
		return nil
	}

	return (*string)(s)
}

type (
	Submission struct {
		Id            string           `json:"id"`
		AgentInfo     *AgentInfo       `json:"agent_info"`
		VacancyInfo   *VacancyInfo     `json:"vacancy_info"`
		CandidateInfo *CandidateInfo   `json:"candidate_info"`
		Status        SubmissionStatus `json:"status"`
	}

	AgentInfo struct {
		Id string `json:"id"`
	}

	VacancyInfo struct {
		Id string `json:"id"`
	}

	CandidateInfo struct {
		Id          string  `json:"id"`
		FirstName   string  `json:"first_name"`
		LastName    string  `json:"last_name"`
		MiddleName  string  `json:"middle_name"`
		PhoneNumber string  `json:"phone_number"`
		Email       string  `json:"email"`
		Birthday    string  `json:"birthday"`
		CvLink      *string `json:"cv_link"`
		Resume      *string `json:"resume"`
	}
)

func (s *Submission) From(msg *dbtypes.Submission) *Submission {
	if msg == nil {
		return nil
	}

	res := &Submission{
		Id:     msg.Id,
		Status: SubmissionStatus(msg.Status),
	}

	if msg.AgentInfo != nil {
		res.AgentInfo = &AgentInfo{
			Id: msg.AgentInfo.Id,
		}
	}

	if msg.VacancyInfo != nil {
		res.VacancyInfo = &VacancyInfo{
			Id: msg.VacancyInfo.Id,
		}
	}

	if msg.CandidateInfo != nil {
		res.CandidateInfo = &CandidateInfo{
			Id:          msg.CandidateInfo.Id,
			FirstName:   msg.CandidateInfo.FirstName,
			LastName:    msg.CandidateInfo.LastName,
			MiddleName:  msg.CandidateInfo.MiddleName,
			PhoneNumber: msg.CandidateInfo.PhoneNumber,
			Email:       msg.CandidateInfo.Email,
			Birthday:    msg.CandidateInfo.Birthday,
			CvLink:      msg.CandidateInfo.CvLink,
			Resume:      msg.CandidateInfo.Resume,
		}
	}

	return res
}

type (
	SubmissionListGetRequest struct {
		AgentId  string
		Filters  *SubmissionListGetFilters
		Page     uint64
		PageSize uint64
	}

	SubmissionListGetFilters struct {
		VacancyId *string
		Status    *SubmissionStatus
	}

	SubmissionListGetResponse struct {
		Submissions []Submission `json:"submissions"`
	}
)

func (r *SubmissionListGetRequest) FromQuery(query url.Values) (*SubmissionListGetRequest, error) {
	if query == nil {
		return nil, nil
	}

	var filters SubmissionListGetFilters

	if val, ok := query["vacancy_id"]; ok {
		filters.VacancyId = &val[0]
	}

	if val, ok := query["status"]; ok {
		status := SubmissionStatus(val[0])
		filters.Status = &status
	}

	res := &SubmissionListGetRequest{
		Filters:  &filters,
		Page:     constants.DefaultPaginationPage,
		PageSize: constants.DefaultPaginationPageSize,
	}

	if val, ok := query["page"]; ok {
		intVal, err := parseUint64(val[0])
		if err != nil {
			return nil, fmt.Errorf("invalid page param: %w", err)
		}

		res.Page = intVal
	}

	if val, ok := query["page_size"]; ok {
		intVal, err := parseUint64(val[0])
		if err != nil {
			return nil, fmt.Errorf("invalid page_size param: %w", err)
		}

		res.PageSize = intVal
	}

	return res, nil
}

func (r *SubmissionListGetRequest) Validate() error {
	if r == nil {
		return fmt.Errorf("%w: request is nil", ErrValidation)
	}

	if r.AgentId == "" {
		return fmt.Errorf("%w: AgentID is required", ErrValidation)
	}

	if r.Filters != nil {
		if r.Filters.Status != nil && !(*r.Filters.Status == SubStatusUnspecified ||
			*r.Filters.Status == SubStatusNew ||
			*r.Filters.Status == SubStatusPending ||
			*r.Filters.Status == SubStatusOnInterview ||
			*r.Filters.Status == SubStatusApproved ||
			*r.Filters.Status == SubStatusCancelled ||
			*r.Filters.Status == SubStatusRejected) {
			return fmt.Errorf("%w: invalid status: %v", ErrValidation, *r.Filters.Status)
		}
	}

	return nil
}

func (r *SubmissionListGetResponse) From(msg *dbtypes.SubmissionListGetResponse) *SubmissionListGetResponse {
	if msg == nil {
		return nil
	}

	res := &SubmissionListGetResponse{
		Submissions: make([]Submission, len(msg.Submissions)),
	}

	for i, subm := range msg.Submissions {
		res.Submissions[i] = *new(Submission).From(&subm)
	}

	return res
}

type (
	SubmissionListForVacancyGetRequest struct {
		VacancyId string
		Filters   *SubmissionListForVacancyGetFilters
		Page      uint64
		PageSize  uint64
	}

	SubmissionListForVacancyGetFilters struct {
		Status *SubmissionStatus
	}

	SubmissionListForVacancyGetResponse struct {
		Submissions []Submission `json:"submissions"`
	}
)

func (r *SubmissionListForVacancyGetRequest) FromQuery(query url.Values) (*SubmissionListForVacancyGetRequest, error) {
	if query == nil {
		return nil, nil
	}

	var filters SubmissionListForVacancyGetFilters

	if val, ok := query["status"]; ok {
		status := SubmissionStatus(val[0])
		filters.Status = &status
	}

	res := &SubmissionListForVacancyGetRequest{
		Filters:  &filters,
		Page:     constants.DefaultPaginationPage,
		PageSize: constants.DefaultPaginationPageSize,
	}

	if val, ok := query["page"]; ok {
		intVal, err := parseUint64(val[0])
		if err != nil {
			return nil, fmt.Errorf("invalid page param: %w", err)
		}

		res.Page = intVal
	}

	if val, ok := query["page_size"]; ok {
		intVal, err := parseUint64(val[0])
		if err != nil {
			return nil, fmt.Errorf("invalid page_size param: %w", err)
		}

		res.PageSize = intVal
	}

	return res, nil
}

func (r *SubmissionListForVacancyGetRequest) Validate() error {
	if r == nil {
		return fmt.Errorf("%w: request is nil", ErrValidation)
	}

	if r.VacancyId == "" {
		return fmt.Errorf("%w: VacancyID is required", ErrValidation)
	}

	if r.Filters != nil {
		if r.Filters.Status != nil && !(*r.Filters.Status == SubStatusUnspecified ||
			*r.Filters.Status == SubStatusNew ||
			*r.Filters.Status == SubStatusPending ||
			*r.Filters.Status == SubStatusOnInterview ||
			*r.Filters.Status == SubStatusApproved ||
			*r.Filters.Status == SubStatusCancelled ||
			*r.Filters.Status == SubStatusRejected) {
			return fmt.Errorf("%w: invalid status: %v", ErrValidation, *r.Filters.Status)
		}
	}

	return nil
}

func (r *SubmissionListForVacancyGetResponse) From(msg *dbtypes.SubmissionListGetResponse) *SubmissionListForVacancyGetResponse {
	if msg == nil {
		return nil
	}

	res := &SubmissionListForVacancyGetResponse{
		Submissions: make([]Submission, len(msg.Submissions)),
	}

	for i, subm := range msg.Submissions {
		res.Submissions[i] = *new(Submission).From(&subm)
	}

	return res
}

type (
	SubmissionCreateRequest struct {
		AgentId       string         `json:"agent_id"`
		VacancyId     string         `json:"vacancy_id"`
		CandidateInfo *CandidateInfo `json:"candidate_info"`
	}

	SubmissionCreateResponse struct {
		Id string `json:"id"`
	}
)

func (r *SubmissionCreateRequest) Validate() error {
	if r == nil {
		return fmt.Errorf("%w: request is nil", ErrValidation)
	}

	if r.AgentId == "" {
		return fmt.Errorf("%w: AgentID is required", ErrValidation)
	}

	if r.VacancyId == "" {
		return fmt.Errorf("%w: VacancyID is required", ErrValidation)
	}

	if r.CandidateInfo == nil {
		return fmt.Errorf("%w: CandidateInfo is required", ErrValidation)
	}

	return nil
}

func (r *SubmissionCreateResponse) From(msg *dbtypes.SubmissionCreateResponse) *SubmissionCreateResponse {
	if msg == nil {
		return nil
	}

	return &SubmissionCreateResponse{
		Id: msg.Id,
	}
}

type (
	SubmissionStatusUpdateRequest struct {
		Id     string
		Status SubmissionStatus `json:"status"`
	}

	SubmissionStatusUpdateResponse struct{}
)

func (r *SubmissionStatusUpdateRequest) Validate() error {
	if r == nil {
		return fmt.Errorf("%w: request is nil", ErrValidation)
	}

	if r.Id == "" {
		return fmt.Errorf("%w: ID is required", ErrValidation)
	}

	if !(r.Status == SubStatusUnspecified ||
		r.Status == SubStatusNew ||
		r.Status == SubStatusPending ||
		r.Status == SubStatusOnInterview ||
		r.Status == SubStatusApproved ||
		r.Status == SubStatusCancelled ||
		r.Status == SubStatusRejected) {
		return fmt.Errorf("%w: invalid status: %v", ErrValidation, r.Status)
	}

	return nil
}

type (
	SubmissionDeleteRequest struct {
		Id string
	}

	SubmissionDeleteResponse struct{}
)

func (r *SubmissionDeleteRequest) Validate() error {
	if r == nil {
		return fmt.Errorf("%w: request is nil", ErrValidation)
	}

	if r.Id == "" {
		return fmt.Errorf("%w: ID is required", ErrValidation)
	}

	return nil
}
