package main

import (
	"context"

	"github.com/jackc/pgx/v5/pgxpool"

	"github.com/TaruLab/keluargamart-backend/internal/db"
	"github.com/TaruLab/keluargamart-backend/internal/salestracking"
)

// EmployeeByUser is the one method employeeLookup needs from the HR store.
// Narrowed to an interface so the resolver can be unit-tested without a
// database and without the concrete repository.
type EmployeeByUser interface {
	EmployeeByUserID(ctx context.Context, userID int64) (db.GetEmployeeByUserIDRow, error)
}

// employeeLookup resolves an authenticated user to the employees row that
// belongs to them, for the two "/me" surfaces keyed on employee identity:
// salestracking's visit schedule and lhpp's own-collection worksheet.
//
// RESOLUTION ORDER, and why there is no third step.
//
//  1. employees.user_id = the caller's id. The sanctioned link, and the only
//     one HR maintains on purpose.
//  2. employees.email = the caller's email. Load-bearing, not a convenience:
//     the seeded Sales Representative account predates the employees link and
//     is matched by email. Dropping this would 404 a real salesperson.
//
// What it used to do, and why that was a data leak rather than a fallback: it
// ended with `SELECT id FROM employees ... ORDER BY id LIMIT 1`, so any user
// without an employees row was handed the FIRST employee in the table. On this
// database that is employee 1, Budi Hartono — so 51 of 58 users, including
// every salesperson, resolved to one person's record and read that person's
// visit schedule and LHPP worksheets. A user with no HR record was served
// another user's data, silently, and nothing in the response indicated it.
//
// Failing closed returns salestracking.ErrNoEmployee instead. Both consumers
// already handle it — salestracking/handler.go answers 404, lhpp/handler.go
// answers 422 with "employee record required" — so a user without an employee
// row gets an honest "no record" rather than somebody else's. On this
// database that is the correct outcome for 51 accounts, and the fix for it is
// an HR record, not a lookup that guesses.
//
// Returning another person's id is never acceptable here regardless of how
// rare "no employee row" is: these endpoints are the caller's own record, so a
// wrong id is a wrong answer with no way for the caller to notice.
func employeeLookup(pool *pgxpool.Pool, hr EmployeeByUser) func(context.Context, int64) (int64, error) {
	return func(ctx context.Context, userID int64) (int64, error) {
		if hr != nil {
			if e, err := hr.EmployeeByUserID(ctx, userID); err == nil && e.ID != 0 {
				return e.ID, nil
			}
		}
		// Email match, so the account whose employees.user_id is NULL still
		// resolves. ORDER BY id keeps the pick stable if two employees ever
		// share an address: today they cannot, but LIMIT 1 without ORDER BY
		// would be an arbitrary choice if they could.
		var empID int64
		err := pool.QueryRow(ctx, `
			SELECT e.id
			FROM employees e
			JOIN users u ON LOWER(u.email) = LOWER(e.email)
			WHERE u.id = $1 AND e.deleted_at IS NULL
			ORDER BY e.id
			LIMIT 1`, userID).Scan(&empID)
		if err == nil && empID != 0 {
			return empID, nil
		}
		return 0, salestracking.ErrNoEmployee
	}
}
