package auth

import (
	"context"
	"errors"
	"fmt"
	"log"
	"time"

	"strings"

	"github.com/rede5/gohorsejobs/backend/internal/core/domain/entity"
	"github.com/rede5/gohorsejobs/backend/internal/core/dto"
	"github.com/rede5/gohorsejobs/backend/internal/core/ports"
)

type RegisterCandidateUseCase struct {
	userRepo     ports.UserRepository
	companyRepo  ports.CompanyRepository
	authService  ports.AuthService
	emailService ports.EmailService
}

func NewRegisterCandidateUseCase(uRepo ports.UserRepository, cRepo ports.CompanyRepository, auth ports.AuthService, email ports.EmailService) *RegisterCandidateUseCase {
	return &RegisterCandidateUseCase{
		userRepo:     uRepo,
		companyRepo:  cRepo,
		authService:  auth,
		emailService: email,
	}
}

func (uc *RegisterCandidateUseCase) Execute(ctx context.Context, input dto.RegisterCandidateRequest) (*dto.AuthResponse, error) {
	// 1. Check if email exists
	exists, _ := uc.userRepo.FindByEmail(ctx, input.Email)
	if exists != nil {
		return nil, errors.New("email already registered")
	}

	// 2. Hash Password
	hashed, err := uc.authService.HashPassword(input.Password)
	if err != nil {
		return nil, err
	}

	// 3. Create Candidate's Personal Tenant/Workspace
	// NOTE: ID is empty - will be auto-generated by DB (SERIAL)
	candidateCompany := entity.NewCompany(
		"", // DB generates SERIAL id
		fmt.Sprintf("Candidate - %s (%d)", input.Name, time.Now().Unix()),
		nil, // No document for candidates
		nil, // No contact - will use user's contact info
	)

	savedCompany, err := uc.companyRepo.Save(ctx, candidateCompany)
	if err != nil {
		return nil, fmt.Errorf("failed to create candidate workspace: %w", err)
	}

	// 4. Create User Entity - ID is auto-generated by DB
	user := entity.NewUser("", savedCompany.ID, input.Name, input.Email)
	user.PasswordHash = hashed

	// Map Profile Fields
	if input.Phone != "" {
		user.Phone = &input.Phone
	}
	if input.Address != "" {
		user.Address = &input.Address
	}
	if input.City != "" {
		user.City = &input.City
	}
	if input.State != "" {
		user.State = &input.State
	}
	if input.ZipCode != "" {
		user.ZipCode = &input.ZipCode
	}

	if input.BirthDate != "" {
		parsedDate, err := time.Parse("2006-01-02", input.BirthDate)
		if err == nil {
			user.BirthDate = &parsedDate
		} else {
			log.Printf("Failed to parse birth date: %v", err)
		}
	}

	if input.Education != "" {
		user.Education = &input.Education
	}
	if input.Experience != "" {
		user.Experience = &input.Experience
	}
	if input.Objective != "" {
		user.Objective = &input.Objective
	}

	// Clean up imports logic inside the block above was bad idea.
	// Fixed by adding import "strings" at top.
	if input.Skills != "" {
		parts := strings.Split(input.Skills, ",")
		for i := range parts {
			parts[i] = strings.TrimSpace(parts[i])
		}
		user.Skills = parts
	}

	// Assign Role
	user.AssignRole(entity.Role{Name: entity.RoleCandidate})

	saved, err := uc.userRepo.Save(ctx, user)
	if err != nil {
		return nil, err
	}

	roles := make([]string, len(saved.Roles))
	for i, r := range saved.Roles {
		roles[i] = r.Name
	}

	// 4.1 Link any existing Guest Applications
	if err := uc.userRepo.LinkGuestApplications(ctx, saved.Email, saved.ID); err != nil {
		log.Printf("[RegisterCandidate] Failed to link legacy applications: %v", err)
		// Don't fail registration
	}

	// 5. Generate Token (Auto-login)
	token, err := uc.authService.GenerateToken(saved.ID, saved.TenantID, roles)
	if err != nil {
		return nil, err
	}

	// 6. Send Welcome Email (Async)
	if uc.emailService != nil {
		// Non-blocking call or handled by service internally (RabbitMQ pub is fast)
		vars := map[string]interface{}{
			"name": saved.Name,
			"link": "https://gohorsejobs.com/dashboard", // TODO: make dynamic
		}
		if err := uc.emailService.SendTemplateEmail(ctx, saved.Email, "welcome-candidate", vars); err != nil {
			log.Printf("[RegisterCandidate] Failed to queue welcome email: %v", err)
			// Don't fail registration
		}
	}

	return &dto.AuthResponse{
		Token: token,
		User: dto.UserResponse{
			ID:        saved.ID,
			Name:      saved.Name,
			Email:     saved.Email,
			Roles:     roles,
			Status:    saved.Status,
			CreatedAt: saved.CreatedAt,
		},
	}, nil
}
