package repository

import (
	"bssapp-backend/models"
	"database/sql"
	"errors"
	"strings"
	"time"

	"github.com/lib/pq"
)

var ErrMkUserNotFound = errors.New("mk_user not found")

type MkUserRepository struct {
	DB *sql.DB
}

func NewMkUserRepository(db *sql.DB) *MkUserRepository {
	return &MkUserRepository{DB: db}
}

// -------------------------------------------------------
// 🔍 GET BY USERNAME
// -------------------------------------------------------
func (r *MkUserRepository) GetByUsername(username string) (*models.MkUser, error) {
	username = strings.TrimSpace(username)

	var u models.MkUser

	err := r.DB.QueryRow(`SELECT
	u.id,
	u.username,
	COALESCE(u.email,'') AS email,
	u.is_active,
	COALESCE(u.password_hash,'') AS password_hash,
	u.force_password_change,

	COALESCE(r.id, 0)     AS role_id,
	COALESCE(r.code, '') AS role_code,

	-- ✅ DEPARTMENTS
	COALESCE(
		array_agg(DISTINCT d.code)
		FILTER (WHERE d.code IS NOT NULL),
		'{}'
	) AS department_codes,
	COALESCE(MAX(n.username), '') AS v3_username,
	COALESCE(MAX(n.user_group_code::text), '') AS v3_usergroup,

	u.password_updated_at,
	u.created_at,
	u.updated_at,
	u.last_login_at

FROM mk_dfusr u

LEFT JOIN dfrole_usr ru
	ON ru.dfusr_id = u.id

LEFT JOIN dfrole r
	ON r.id = ru.dfrole_id

-- ✅ USER → DEPT
LEFT JOIN dfusr_dprt ud
	ON ud.dfusr_id = u.id
	AND ud.is_active = true

LEFT JOIN mk_dprt d
	ON d.id = ud.dprt_id

LEFT JOIN dfusr_nebim_user un
	ON un.dfusr_id = u.id

LEFT JOIN mk_nebim_user n
	ON n.id = un.mk_nebim_user_id
	AND n.is_active = true

WHERE LOWER(u.username) = LOWER($1)

GROUP BY
	u.id, r.id

LIMIT 1
`, username).Scan(
		&u.ID,
		&u.Username,
		&u.Email,
		&u.IsActive,
		&u.PasswordHash,
		&u.ForcePasswordChange,

		&u.RoleID,
		&u.RoleCode,

		pq.Array(&u.DepartmentCodes), // ✅
		&u.V3Username,
		&u.V3UserGroup,

		&u.PasswordUpdatedAt,

		&u.CreatedAt,
		&u.UpdatedAt,
		&u.LastLoginAt,
	)

	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, ErrMkUserNotFound
		}
		return nil, err
	}

	return &u, nil
}

// -------------------------------------------------------
// 🔍 GET BY ID
// -------------------------------------------------------
func (r *MkUserRepository) GetByID(id int64) (*models.MkUser, error) {
	var u models.MkUser

	err := r.DB.QueryRow(`
		SELECT
	u.id,
	u.username,
	COALESCE(u.email,'') AS email,
	u.is_active,
	COALESCE(u.password_hash,'') AS password_hash,
	u.force_password_change,

	COALESCE(r.id, 0)     AS role_id,
	COALESCE(r.code, '') AS role_code,

	-- ✅ DEPARTMENTS
	COALESCE(
		array_agg(DISTINCT d.code)
		FILTER (WHERE d.code IS NOT NULL),
		'{}'
	) AS department_codes,
	COALESCE(MAX(n.username), '') AS v3_username,
	COALESCE(MAX(n.user_group_code::text), '') AS v3_usergroup,

	u.password_updated_at,
	u.created_at,
	u.updated_at,
	u.last_login_at

FROM mk_dfusr u

LEFT JOIN dfrole_usr ru
	ON ru.dfusr_id = u.id

LEFT JOIN dfrole r
	ON r.id = ru.dfrole_id

-- ✅ USER → DEPT
LEFT JOIN dfusr_dprt ud
	ON ud.dfusr_id = u.id
	AND ud.is_active = true

LEFT JOIN mk_dprt d
	ON d.id = ud.dprt_id

LEFT JOIN dfusr_nebim_user un
	ON un.dfusr_id = u.id

LEFT JOIN mk_nebim_user n
	ON n.id = un.mk_nebim_user_id
	AND n.is_active = true

WHERE u.id = $1

GROUP BY
	u.id, r.id

LIMIT 1
`, id).Scan(
		&u.ID,
		&u.Username,
		&u.Email,
		&u.IsActive,
		&u.PasswordHash,
		&u.ForcePasswordChange,

		&u.RoleID,
		&u.RoleCode,
		pq.Array(&u.DepartmentCodes), // ✅
		&u.V3Username,
		&u.V3UserGroup,
		&u.PasswordUpdatedAt,
		&u.CreatedAt,
		&u.UpdatedAt,
		&u.LastLoginAt,
	)

	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, ErrMkUserNotFound
		}
		return nil, err
	}

	return &u, nil
}

// -------------------------------------------------------
// 🔁 CREATE FROM LEGACY (dfusr → mk_dfusr)
// - id = dfusr.id  ✅
// - role / v3 YOK
// -------------------------------------------------------
// -------------------------------------------------------
// 🔁 CREATE FROM LEGACY (dfusr → mk_dfusr) FULL MIGRATION
// -------------------------------------------------------
func (r *MkUserRepository) CreateFromLegacy(
	legacy *models.User,
	passwordHash string,
) (*models.MkUser, error) {

	var u models.MkUser

	err := r.DB.QueryRow(`
		INSERT INTO mk_dfusr (
			id,
			username,
			email,
			full_name,
			mobile,
			address,
			is_active,
			password_hash,
			force_password_change,
			created_at,
			updated_at
		)
		VALUES (
			$1,$2,$3,$4,$5,$6,$7,$8,true,now(),now()
		)
		ON CONFLICT (id)
		DO UPDATE SET
			email                = EXCLUDED.email,
			full_name            = EXCLUDED.full_name,
			mobile               = EXCLUDED.mobile,
			address              = EXCLUDED.address,
			password_hash        = EXCLUDED.password_hash,
			force_password_change= true,
			updated_at           = now()
		RETURNING
			id,
			username,
			COALESCE(email,''),
			is_active,
			COALESCE(password_hash,''),
			force_password_change,
			password_updated_at,
			created_at,
			updated_at,
			last_login_at
	`,
		legacy.ID,
		legacy.Username,
		legacy.Email,
		legacy.FullName,
		legacy.Mobile,
		legacy.Address,
		legacy.IsActive,
		passwordHash,
	).Scan(
		&u.ID,
		&u.Username,
		&u.Email,
		&u.IsActive,
		&u.PasswordHash,
		&u.ForcePasswordChange,
		&u.PasswordUpdatedAt,
		&u.CreatedAt,
		&u.UpdatedAt,
		&u.LastLoginAt,
	)

	if err != nil {
		return nil, err
	}

	return &u, nil
}

// -------------------------------------------------------
// ➕ CREATE NEW USER (NON-LEGACY)
// - id = sequence (>=1000)
// -------------------------------------------------------
func (r *MkUserRepository) CreateNewUser(
	username string,
	email string,
	isActive bool,
) (*models.MkUser, error) {

	var u models.MkUser

	err := r.DB.QueryRow(`
		INSERT INTO mk_dfusr (
			username,
			email,
			is_active,
			force_password_change,
			created_at,
			updated_at
		)
		VALUES (
			$1,$2,$3,true,now(),now()
		)
		RETURNING
			id,
			username,
			COALESCE(email,'') AS email,
			is_active,
			COALESCE(password_hash,'') AS password_hash,
			force_password_change,
			password_updated_at,
			created_at,
			updated_at,
			last_login_at
	`,
		strings.TrimSpace(username),
		strings.TrimSpace(email),
		isActive,
	).Scan(
		&u.ID,
		&u.Username,
		&u.Email,
		&u.IsActive,
		&u.PasswordHash,
		&u.ForcePasswordChange,
		&u.PasswordUpdatedAt,
		&u.CreatedAt,
		&u.UpdatedAt,
		&u.LastLoginAt,
	)

	if err != nil {
		return nil, err
	}

	return &u, nil
}

// -------------------------------------------------------
// 🕒 TOUCH LAST LOGIN
// -------------------------------------------------------
func (r *MkUserRepository) TouchLastLogin(userID int64) error {
	_, err := r.DB.Exec(`
		UPDATE mk_dfusr
		SET last_login_at = $1,
		    updated_at = $1
		WHERE id = $2
	`, time.Now(), userID)
	return err
}

// -------------------------------------------------------
// 🔐 UPDATE PASSWORD
// -------------------------------------------------------
func (r *MkUserRepository) UpdatePassword(userID int64, newHash string) error {
	_, err := r.DB.Exec(`
		UPDATE mk_dfusr
		SET
			password_hash = $1,
			force_password_change = false,
			password_updated_at = NOW(),
			updated_at = NOW()
		WHERE id = $2
	`, newHash, userID)
	return err
}
