package service

import (
	"context"
	"time"

	actionsignoff "wucher/internal/domain/action_signoff"
)

type ActionSignoffService struct{ repo actionsignoff.Repository }

func NewActionSignoffService(repo actionsignoff.Repository) *ActionSignoffService {
	return &ActionSignoffService{repo: repo}
}

func (s *ActionSignoffService) GetByFlight(ctx context.Context, flightID []byte) (*actionsignoff.ActionSignoff, error) {
	return s.repo.GetByFlight(ctx, flightID)
}

func (s *ActionSignoffService) GetByComplaint(ctx context.Context, complaintID []byte) (*actionsignoff.ActionSignoff, error) {
	return s.repo.GetByComplaint(ctx, complaintID)
}

func (s *ActionSignoffService) GetByComplaintIDs(ctx context.Context, complaintIDs [][]byte) (map[string]*actionsignoff.ActionSignoff, error) {
	return s.repo.GetByComplaintIDs(ctx, complaintIDs)
}

// UnsignByComplaint clears the signature on the complaint-linked sign-off. No-op when
// there is no sign-off for the complaint or it is already unsigned.
func (s *ActionSignoffService) UnsignByComplaint(ctx context.Context, complaintID []byte) (*actionsignoff.ActionSignoff, error) {
	row, err := s.repo.GetByComplaint(ctx, complaintID)
	if err != nil {
		return nil, err
	}
	if row == nil {
		return nil, nil
	}
	if row.SignedAt == nil {
		return row, nil
	}
	row.SignedAt = nil
	row.SignedBy = nil
	if err := s.repo.Update(ctx, row); err != nil {
		return nil, err
	}
	return row, nil
}

// SignForComplaint records (or re-stamps) the action sign-off linked to a specific
// complaint — i.e. "this complaint's corrective action was signed off". Upsert by
// complaint: creates the row on first sign, otherwise re-stamps signer/time.
func (s *ActionSignoffService) SignForComplaint(ctx context.Context, complaintID, flightID, helicopterID []byte, signer []byte) (*actionsignoff.ActionSignoff, error) {
	row, err := s.repo.GetByComplaint(ctx, complaintID)
	if err != nil {
		return nil, err
	}
	now := time.Now().UTC()
	if row == nil {
		row = &actionsignoff.ActionSignoff{
			HelicopterID: append([]byte(nil), helicopterID...),
			FlightID:     append([]byte(nil), flightID...),
			ComplaintID:  append([]byte(nil), complaintID...),
			SignedAt:     &now,
			SignedBy:     append([]byte(nil), signer...),
		}
		if err := s.repo.Create(ctx, row); err != nil {
			return nil, err
		}
		return row, nil
	}
	row.FlightID = append([]byte(nil), flightID...)
	row.SignedAt = &now
	row.SignedBy = append([]byte(nil), signer...)
	if err := s.repo.Update(ctx, row); err != nil {
		return nil, err
	}
	return row, nil
}

// Sign records (or re-stamps) the helicopter's action sign-off as signed by the

func (s *ActionSignoffService) Sign(ctx context.Context, flightID, helicopterID []byte, signer []byte) (*actionsignoff.ActionSignoff, error) {
	row, err := s.repo.GetByFlight(ctx, flightID)
	if err != nil {
		return nil, err
	}
	now := time.Now().UTC()
	if row == nil {
		row = &actionsignoff.ActionSignoff{
			HelicopterID: append([]byte(nil), helicopterID...),
			FlightID:     append([]byte(nil), flightID...),
			SignedAt:     &now,
			SignedBy:     append([]byte(nil), signer...),
		}
		if err := s.repo.Create(ctx, row); err != nil {
			return nil, err
		}
		return row, nil
	}
	row.SignedAt = &now
	row.SignedBy = append([]byte(nil), signer...)
	if err := s.repo.Update(ctx, row); err != nil {
		return nil, err
	}
	return row, nil
}

// Unsign clears the signature (check → uncheck). Returns ErrNotFound when there
// is nothing to unsign.
func (s *ActionSignoffService) Unsign(ctx context.Context, flightID []byte, _ []byte) (*actionsignoff.ActionSignoff, error) {
	row, err := s.repo.GetByFlight(ctx, flightID)
	if err != nil {
		return nil, err
	}
	if row == nil {
		return nil, actionsignoff.ErrNotFound
	}
	row.SignedAt = nil
	row.SignedBy = nil
	if err := s.repo.Update(ctx, row); err != nil {
		return nil, err
	}
	return row, nil
}
