package finance

import (
	"context"

	"github.com/TaruLab/keluargamart-backend/internal/auth"
	"github.com/TaruLab/keluargamart-backend/internal/uploads"
)

// ProofVerifyPermission is the permission that grants access to ANY payment
// proof regardless of ownership. It is the only finance-specific rule the
// /uploads read path needs, and keeping it here means the write path and the
// read path cannot name two different permissions.
const ProofVerifyPermission = "fakturisasi.payments.verify"

// CanAccessPaymentProof is the single authorization rule for proofs:
// the owning buyer (payment -> invoice -> customers.user_id) or staff holding
// ProofVerifyPermission, or operational staff holding delivery/sales order view permissions.
//
// ownerUserID == 0 means the payment's customer has no linked user, which
// denies the owner branch and leaves only the permission. Both the proof
// upload (write) path and the proof read path call this — they must not drift.
func CanAccessPaymentProof(u *auth.User, ownerUserID int64) bool {
	if u == nil {
		return false
	}
	if ownerUserID != 0 && ownerUserID == u.ID {
		return true
	}
	return u.Can(ProofVerifyPermission) ||
		u.Can("distribution.delivery-orders.view") ||
		u.Can("distribution.shipments.view") ||
		u.Can("sales.sales-orders.view")
}

// PaymentProofKeyOwner resolves the owner of the payment proof stored under
// key, authoritatively, from the payments table. isProof=false means no
// payment references the key, so the object is an ordinary (public) image.
// ownerUserID is 0 when the payment's customer has no linked user: the document
// stays private, readable only with ProofVerifyPermission.
//
// One upload yields one server-generated key, so a key maps to at most one
// payment; ORDER BY user_id NULLS LAST in the query only makes the choice
// deterministic.
func (s *Service) PaymentProofKeyOwner(ctx context.Context, key string) (ownerUserID int64, isProof bool, err error) {
	owners, found, err := s.store.PaymentProofOwnersByKey(ctx, key)
	if err != nil || !found {
		return 0, false, err
	}
	if len(owners) > 0 {
		return owners[0], true, nil
	}
	return 0, true, nil
}

// ProofAccess is the internal/uploads read-path seam, backed by the payments
// table. It is injected into the uploads handler (which must not import this
// package) so that proofs are authorized on READ as well as on write —
// including proofs stored under legacy single-segment keys, which carry no
// proof marker and can only be recognised by consulting the table.
func (s *Service) ProofAccess(ctx context.Context, key string, u *auth.User) (uploads.ProofAccess, error) {
	ownerUserID, isProof, err := s.PaymentProofKeyOwner(ctx, key)
	if err != nil {
		return uploads.ProofAccess{}, err
	}
	if !isProof && !uploads.IsProofKey(key) {
		return uploads.ProofAccess{}, nil // public image
	}
	return uploads.ProofAccess{Private: true, Allowed: CanAccessPaymentProof(u, ownerUserID)}, nil
}
