package sales

import (
	"context"
	"encoding/json"

	"github.com/TaruLab/keluargamart-backend/internal/db"
	"errors"
	"net/http"
	"strings"

	"github.com/TaruLab/keluargamart-backend/internal/auth"
	"github.com/TaruLab/keluargamart-backend/pkg/httpresponse"
	"github.com/TaruLab/keluargamart-backend/pkg/middleware"
)

// Delivery/pickup proof (migration 000142): the buyer MAY attach a photo taken
// when the goods change hands. It is evidence, not a gate — confirming without
// one stays valid — and the URL must point at the uploads store this server
// itself served (POST /api/v1/uploads), so a caller cannot smuggle an arbitrary
// external URL into the order record.
const receivedProofURLPrefix = "/uploads/"

// AttachReceivedProof records the buyer's delivery/pickup proof photo on the
// order. Allowed for the owning buyer while the order is in a pre-terminal
// state; staff may attach one on the buyer's behalf at any pre-terminal state
// (e.g. the till noticing the buyer left without completing the flow).
//
// Ownership is checked against the ORDER's customer (CustomerByUserID), never
// against a caller-supplied id — an earlier draft compared u.ID to a parameter
// the handler filled with the caller's own id, which made every buyer an owner
// of every order.
func (s *Service) AttachReceivedProof(ctx context.Context, orderID int64, _ int64, url string) (*SalesOrder, error) {
	u := auth.UserFrom(ctx)
	if u == nil {
		return nil, ErrNotFound
	}
	url = strings.TrimSpace(url)
	if url == "" {
		return nil, errors.New("proof url is required")
	}
	if !strings.HasPrefix(url, receivedProofURLPrefix) {
		return nil, errors.New("proof must be an uploaded file under /uploads/")
	}

	tx, err := s.store.Begin(ctx)
	if err != nil {
		return nil, err
	}
	defer tx.Rollback(ctx)

	row, err := s.store.OrderByIDForUpdate(ctx, tx, orderID)
	if err != nil {
		return nil, err
	}
	o := orderFromLockedRow(row)
	if err := s.checkScope(ctx, o.StoreID); err != nil {
		return nil, err
	}

	// Ownership: a buyer is the owner only when the order's customer row is
	// the one linked to THEIR user id. Staff roles are order-agnostic here —
	// they attach on the buyer's behalf at the counter.
	isStaff := u.Role == auth.RoleWarehouse || u.Role == auth.RoleAdmin || u.Role == auth.RoleOwner ||
		u.Role == auth.RoleStoreManager || u.Role == auth.RoleCashier
	if !isStaff {
		if u.Role != auth.RoleBuyer && u.Role != "customer" && u.Role != "b2b_client" {
			return nil, ErrNotFound
		}
		custID, err := s.store.CustomerByUserID(ctx, tx, u.ID)
		if err != nil || custID != o.CustomerID {
			return nil, ErrNotFound
		}
	}

	if isTerminalStatus(o.Status) {
		return nil, ErrInvalidStatus
	}

	if err := s.store.SetReceivedProofURL(ctx, tx, orderID, url); err != nil {
		return nil, err
	}
	if err := tx.Commit(ctx); err != nil {
		return nil, err
	}
	return s.Get(ctx, orderID)
}

func isTerminalStatus(status string) bool {
	return status == "delivered" || status == "cancelled" || status == "rejected"
}

// SetReceivedProofURL persists the proof reference on the order.
func (r *Repository) SetReceivedProofURL(ctx context.Context, q db.DBTX, id int64, url string) error {
	_, err := r.execer(q).Exec(ctx,
		`UPDATE sales_orders SET received_proof_url = $2, updated_at = now() WHERE id = $1`,
		id, url)
	return err
}

// Handler: PATCH /sales-orders/{id}/received-proof { url }
func (h *Handler) AttachReceivedProof(w http.ResponseWriter, r *http.Request) {
	reqID := middleware.RequestIDFrom(r.Context())
	u := auth.UserFrom(r.Context())
	if u == nil {
		httpresponse.Error(w, http.StatusUnauthorized, reqID, httpresponse.CodeAuthentication, "Unauthenticated", nil)
		return
	}
	var in struct {
		URL string `json:"url"`
	}
	if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
		httpresponse.Error(w, http.StatusBadRequest, reqID, httpresponse.CodeValidation, "invalid request body", nil)
		return
	}
	o, err := h.svc.AttachReceivedProof(r.Context(), pathID(r), u.ID, in.URL)
	if err != nil {
		respondErr(w, r, err)
		return
	}
	httpresponse.OK(w, http.StatusOK, reqID, o)
}
