package service

import (
	"context"
	"fmt"

	flightinspection "wucher/internal/domain/flight_inspection"
	flightprepcheck "wucher/internal/domain/flight_prep_check"
	"wucher/internal/shared/pkg/appctx"
)

type FlightPrepCheckService struct {
	checkRepo      flightprepcheck.Repository
	inspectionRepo flightinspection.FlightInspectionRepository
}

func NewFlightPrepCheckService(
	checkRepo flightprepcheck.Repository,
	inspectionRepo flightinspection.FlightInspectionRepository,
) *FlightPrepCheckService {
	return &FlightPrepCheckService{
		checkRepo:      checkRepo,
		inspectionRepo: inspectionRepo,
	}
}

func (s *FlightPrepCheckService) InitializeChecks(ctx context.Context, flightInspectionID []byte) (int, error) {
	if len(flightInspectionID) != 16 {
		return 0, &flightprepcheck.ValidationError{Status: 400, Title: "Invalid ID", Detail: "flight_inspection_id must be a valid UUID"}
	}

	inspection, err := s.inspectionRepo.GetByID(ctx, flightInspectionID)
	if err != nil {
		return 0, fmt.Errorf("failed to check flight inspection: %w", err)
	}
	if inspection == nil {
		return 0, &flightprepcheck.ValidationError{Status: 404, Title: "Not found", Detail: "flight inspection not found"}
	}

	existing, err := s.checkRepo.GetByFlightInspectionID(ctx, flightInspectionID)
	if err != nil {
		return 0, fmt.Errorf("failed to get prep check: %w", err)
	}
	if existing != nil {
		return 0, nil
	}

	row := &flightprepcheck.FlightPrepCheck{
		FlightInspectionID: flightInspectionID,
	}
	if userID := appctx.GetUserID(ctx); userID != nil {
		row.CreatedBy = userID
		row.UpdatedBy = userID
	}
	if err := s.checkRepo.Create(ctx, row); err != nil {
		return 0, fmt.Errorf("failed to create prep check: %w", err)
	}

	return 1, nil
}

func (s *FlightPrepCheckService) GetByFlightInspection(ctx context.Context, flightInspectionID []byte) (*flightprepcheck.FlightPrepCheck, error) {
	if len(flightInspectionID) != 16 {
		return nil, &flightprepcheck.ValidationError{Status: 400, Title: "Invalid ID", Detail: "flight_inspection_id must be a valid UUID"}
	}

	inspection, err := s.inspectionRepo.GetByID(ctx, flightInspectionID)
	if err != nil {
		return nil, fmt.Errorf("failed to check flight inspection: %w", err)
	}
	if inspection == nil {
		return nil, &flightprepcheck.ValidationError{Status: 404, Title: "Not found", Detail: "flight inspection not found"}
	}

	return s.checkRepo.GetByFlightInspectionID(ctx, flightInspectionID)
}

func (s *FlightPrepCheckService) UpdateCheck(ctx context.Context, checkID []byte, req *flightprepcheck.UpsertRequest) (*flightprepcheck.FlightPrepCheck, error) {
	if len(checkID) != 16 {
		return nil, &flightprepcheck.ValidationError{Status: 400, Title: "Invalid ID", Detail: "check_id must be a valid UUID"}
	}
	existing, err := s.checkRepo.GetByID(ctx, checkID)
	if err != nil {
		return nil, fmt.Errorf("failed to get prep check: %w", err)
	}
	if existing == nil {
		return nil, &flightprepcheck.ValidationError{Status: 404, Title: "Not found", Detail: "flight prep check not found"}
	}
	applyFlightPrepCheckUpsert(existing, req)
	if userID := appctx.GetUserID(ctx); userID != nil {
		existing.UpdatedBy = userID
	}
	if err := s.checkRepo.Update(ctx, existing); err != nil {
		return nil, fmt.Errorf("failed to update prep check: %w", err)
	}
	return existing, nil
}

func (s *FlightPrepCheckService) UpsertByFlightInspection(ctx context.Context, flightInspectionID []byte, req *flightprepcheck.UpsertRequest) (*flightprepcheck.FlightPrepCheck, error) {
	if len(flightInspectionID) != 16 {
		return nil, &flightprepcheck.ValidationError{Status: 400, Title: "Invalid ID", Detail: "flight_inspection_id must be a valid UUID"}
	}
	inspection, err := s.inspectionRepo.GetByID(ctx, flightInspectionID)
	if err != nil {
		return nil, fmt.Errorf("failed to check flight inspection: %w", err)
	}
	if inspection == nil {
		return nil, &flightprepcheck.ValidationError{Status: 404, Title: "Not found", Detail: "flight inspection not found"}
	}

	existing, err := s.checkRepo.GetByFlightInspectionID(ctx, flightInspectionID)
	if err != nil {
		return nil, fmt.Errorf("failed to get prep check: %w", err)
	}
	if existing == nil {
		existing = &flightprepcheck.FlightPrepCheck{FlightInspectionID: flightInspectionID}
		if userID := appctx.GetUserID(ctx); userID != nil {
			existing.CreatedBy = userID
			existing.UpdatedBy = userID
		}
		applyFlightPrepCheckUpsert(existing, req)
		if err := s.checkRepo.Create(ctx, existing); err != nil {
			return nil, fmt.Errorf("failed to create prep check: %w", err)
		}
		return existing, nil
	}

	applyFlightPrepCheckUpsert(existing, req)
	if userID := appctx.GetUserID(ctx); userID != nil {
		existing.UpdatedBy = userID
	}
	if err := s.checkRepo.Update(ctx, existing); err != nil {
		return nil, fmt.Errorf("failed to update prep check: %w", err)
	}
	return existing, nil
}

func applyFlightPrepCheckUpsert(row *flightprepcheck.FlightPrepCheck, req *flightprepcheck.UpsertRequest) {
	if row == nil || req == nil {
		return
	}
	if req.NOTAMBriefing != nil {
		row.NOTAMBriefing = *req.NOTAMBriefing
	}
	if req.WeatherBriefing != nil {
		row.WeatherBriefing = *req.WeatherBriefing
	}
	if req.OperationalFlightPlan != nil {
		row.OperationalFlightPlan = *req.OperationalFlightPlan
	}
}
