// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.31.1
// source: hr.sql

package db

import (
	"context"

	"github.com/jackc/pgx/v5/pgtype"
	"github.com/shopspring/decimal"
)

const countAttendance = `-- name: CountAttendance :one
SELECT count(*) FROM attendances
WHERE ($1::bigint IS NULL OR employee_id = $1)
  AND ($2::text IS NULL OR status = $2)
  AND ($3::date IS NULL OR attendance_date >= $3)
  AND ($4::date IS NULL OR attendance_date <= $4)
`

type CountAttendanceParams struct {
	EmployeeID pgtype.Int8 `json:"employee_id"`
	Status     pgtype.Text `json:"status"`
	DateFrom   pgtype.Date `json:"date_from"`
	DateTo     pgtype.Date `json:"date_to"`
}

func (q *Queries) CountAttendance(ctx context.Context, arg CountAttendanceParams) (int64, error) {
	row := q.db.QueryRow(ctx, countAttendance,
		arg.EmployeeID,
		arg.Status,
		arg.DateFrom,
		arg.DateTo,
	)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const countEmployees = `-- name: CountEmployees :one
SELECT count(*) FROM employees
WHERE deleted_at IS NULL
  AND ($1::text IS NULL OR (name ILIKE '%' || $1 || '%' OR nik ILIKE '%' || $1 || '%' OR employee_number ILIKE '%' || $1 || '%'))
  AND ($2::boolean IS NULL OR is_active = $2)
`

type CountEmployeesParams struct {
	Search pgtype.Text `json:"search"`
	Active pgtype.Bool `json:"active"`
}

func (q *Queries) CountEmployees(ctx context.Context, arg CountEmployeesParams) (int64, error) {
	row := q.db.QueryRow(ctx, countEmployees, arg.Search, arg.Active)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const countLeaves = `-- name: CountLeaves :one
SELECT count(*) FROM leaves
WHERE ($1::bigint IS NULL OR employee_id = $1)
  AND ($2::text IS NULL OR status = $2)
  AND ($3::date IS NULL OR start_date >= $3)
  AND ($4::date IS NULL OR start_date <= $4)
`

type CountLeavesParams struct {
	EmployeeID pgtype.Int8 `json:"employee_id"`
	Status     pgtype.Text `json:"status"`
	DateFrom   pgtype.Date `json:"date_from"`
	DateTo     pgtype.Date `json:"date_to"`
}

func (q *Queries) CountLeaves(ctx context.Context, arg CountLeavesParams) (int64, error) {
	row := q.db.QueryRow(ctx, countLeaves,
		arg.EmployeeID,
		arg.Status,
		arg.DateFrom,
		arg.DateTo,
	)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const countPayrolls = `-- name: CountPayrolls :one
SELECT count(*) FROM payrolls
WHERE ($1::bigint IS NULL OR employee_id = $1)
  AND ($2::text IS NULL OR status = $2)
`

type CountPayrollsParams struct {
	EmployeeID pgtype.Int8 `json:"employee_id"`
	Status     pgtype.Text `json:"status"`
}

func (q *Queries) CountPayrolls(ctx context.Context, arg CountPayrollsParams) (int64, error) {
	row := q.db.QueryRow(ctx, countPayrolls, arg.EmployeeID, arg.Status)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const countPerformances = `-- name: CountPerformances :one
SELECT count(*) FROM performances
`

func (q *Queries) CountPerformances(ctx context.Context) (int64, error) {
	row := q.db.QueryRow(ctx, countPerformances)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const createAttendance = `-- name: CreateAttendance :one
INSERT INTO attendances (employee_id, attendance_date, clock_in, clock_out,
       clock_in_lat, clock_in_lng, clock_out_lat, clock_out_lng, status, work_hours,
       overtime_hours, notes)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12)
RETURNING id, employee_id, attendance_date::text, clock_in, clock_out,
       clock_in_lat, clock_in_lng, clock_out_lat, clock_out_lng, status, work_hours,
       overtime_hours, notes
`

type CreateAttendanceParams struct {
	EmployeeID     int64               `json:"employee_id"`
	AttendanceDate pgtype.Date         `json:"attendance_date"`
	ClockIn        pgtype.Timestamptz  `json:"clock_in"`
	ClockOut       pgtype.Timestamptz  `json:"clock_out"`
	ClockInLat     decimal.NullDecimal `json:"clock_in_lat"`
	ClockInLng     decimal.NullDecimal `json:"clock_in_lng"`
	ClockOutLat    decimal.NullDecimal `json:"clock_out_lat"`
	ClockOutLng    decimal.NullDecimal `json:"clock_out_lng"`
	Status         string              `json:"status"`
	WorkHours      decimal.NullDecimal `json:"work_hours"`
	OvertimeHours  decimal.NullDecimal `json:"overtime_hours"`
	Notes          pgtype.Text         `json:"notes"`
}

type CreateAttendanceRow struct {
	ID             int64               `json:"id"`
	EmployeeID     int64               `json:"employee_id"`
	AttendanceDate string              `json:"attendance_date"`
	ClockIn        pgtype.Timestamptz  `json:"clock_in"`
	ClockOut       pgtype.Timestamptz  `json:"clock_out"`
	ClockInLat     decimal.NullDecimal `json:"clock_in_lat"`
	ClockInLng     decimal.NullDecimal `json:"clock_in_lng"`
	ClockOutLat    decimal.NullDecimal `json:"clock_out_lat"`
	ClockOutLng    decimal.NullDecimal `json:"clock_out_lng"`
	Status         string              `json:"status"`
	WorkHours      decimal.NullDecimal `json:"work_hours"`
	OvertimeHours  decimal.NullDecimal `json:"overtime_hours"`
	Notes          pgtype.Text         `json:"notes"`
}

func (q *Queries) CreateAttendance(ctx context.Context, arg CreateAttendanceParams) (CreateAttendanceRow, error) {
	row := q.db.QueryRow(ctx, createAttendance,
		arg.EmployeeID,
		arg.AttendanceDate,
		arg.ClockIn,
		arg.ClockOut,
		arg.ClockInLat,
		arg.ClockInLng,
		arg.ClockOutLat,
		arg.ClockOutLng,
		arg.Status,
		arg.WorkHours,
		arg.OvertimeHours,
		arg.Notes,
	)
	var i CreateAttendanceRow
	err := row.Scan(
		&i.ID,
		&i.EmployeeID,
		&i.AttendanceDate,
		&i.ClockIn,
		&i.ClockOut,
		&i.ClockInLat,
		&i.ClockInLng,
		&i.ClockOutLat,
		&i.ClockOutLng,
		&i.Status,
		&i.WorkHours,
		&i.OvertimeHours,
		&i.Notes,
	)
	return i, err
}

const createEmployee = `-- name: CreateEmployee :one
INSERT INTO employees (employee_number, user_id, name, nik, department, job_level, position,
       employment_type, join_date, end_date, basic_salary, allowance, phone, email, address, city,
       bank_name, bank_account, bank_account_name, npwp, bpjs_ketenagakerjaan_no, bpjs_kesehatan_no, photo, is_active)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24)
RETURNING id, employee_number, user_id, name, nik, department, job_level, position,
       employment_type, join_date, end_date, basic_salary, allowance, phone, email, address, city,
       bank_name, bank_account, bank_account_name, npwp, bpjs_ketenagakerjaan_no, bpjs_kesehatan_no, photo, is_active, leave_balance, leave_used, deleted_at
`

type CreateEmployeeParams struct {
	EmployeeNumber        string          `json:"employee_number"`
	UserID                pgtype.Int8     `json:"user_id"`
	Name                  string          `json:"name"`
	Nik                   pgtype.Text     `json:"nik"`
	Department            string          `json:"department"`
	JobLevel              string          `json:"job_level"`
	Position              pgtype.Text     `json:"position"`
	EmploymentType        string          `json:"employment_type"`
	JoinDate              pgtype.Date     `json:"join_date"`
	EndDate               pgtype.Date     `json:"end_date"`
	BasicSalary           decimal.Decimal `json:"basic_salary"`
	Allowance             decimal.Decimal `json:"allowance"`
	Phone                 pgtype.Text     `json:"phone"`
	Email                 pgtype.Text     `json:"email"`
	Address               pgtype.Text     `json:"address"`
	City                  pgtype.Text     `json:"city"`
	BankName              pgtype.Text     `json:"bank_name"`
	BankAccount           pgtype.Text     `json:"bank_account"`
	BankAccountName       pgtype.Text     `json:"bank_account_name"`
	Npwp                  pgtype.Text     `json:"npwp"`
	BpjsKetenagakerjaanNo pgtype.Text     `json:"bpjs_ketenagakerjaan_no"`
	BpjsKesehatanNo       pgtype.Text     `json:"bpjs_kesehatan_no"`
	Photo                 pgtype.Text     `json:"photo"`
	IsActive              bool            `json:"is_active"`
}

type CreateEmployeeRow struct {
	ID                    int64              `json:"id"`
	EmployeeNumber        string             `json:"employee_number"`
	UserID                pgtype.Int8        `json:"user_id"`
	Name                  string             `json:"name"`
	Nik                   pgtype.Text        `json:"nik"`
	Department            string             `json:"department"`
	JobLevel              string             `json:"job_level"`
	Position              pgtype.Text        `json:"position"`
	EmploymentType        string             `json:"employment_type"`
	JoinDate              pgtype.Date        `json:"join_date"`
	EndDate               pgtype.Date        `json:"end_date"`
	BasicSalary           decimal.Decimal    `json:"basic_salary"`
	Allowance             decimal.Decimal    `json:"allowance"`
	Phone                 pgtype.Text        `json:"phone"`
	Email                 pgtype.Text        `json:"email"`
	Address               pgtype.Text        `json:"address"`
	City                  pgtype.Text        `json:"city"`
	BankName              pgtype.Text        `json:"bank_name"`
	BankAccount           pgtype.Text        `json:"bank_account"`
	BankAccountName       pgtype.Text        `json:"bank_account_name"`
	Npwp                  pgtype.Text        `json:"npwp"`
	BpjsKetenagakerjaanNo pgtype.Text        `json:"bpjs_ketenagakerjaan_no"`
	BpjsKesehatanNo       pgtype.Text        `json:"bpjs_kesehatan_no"`
	Photo                 pgtype.Text        `json:"photo"`
	IsActive              bool               `json:"is_active"`
	LeaveBalance          decimal.Decimal    `json:"leave_balance"`
	LeaveUsed             decimal.Decimal    `json:"leave_used"`
	DeletedAt             pgtype.Timestamptz `json:"deleted_at"`
}

func (q *Queries) CreateEmployee(ctx context.Context, arg CreateEmployeeParams) (CreateEmployeeRow, error) {
	row := q.db.QueryRow(ctx, createEmployee,
		arg.EmployeeNumber,
		arg.UserID,
		arg.Name,
		arg.Nik,
		arg.Department,
		arg.JobLevel,
		arg.Position,
		arg.EmploymentType,
		arg.JoinDate,
		arg.EndDate,
		arg.BasicSalary,
		arg.Allowance,
		arg.Phone,
		arg.Email,
		arg.Address,
		arg.City,
		arg.BankName,
		arg.BankAccount,
		arg.BankAccountName,
		arg.Npwp,
		arg.BpjsKetenagakerjaanNo,
		arg.BpjsKesehatanNo,
		arg.Photo,
		arg.IsActive,
	)
	var i CreateEmployeeRow
	err := row.Scan(
		&i.ID,
		&i.EmployeeNumber,
		&i.UserID,
		&i.Name,
		&i.Nik,
		&i.Department,
		&i.JobLevel,
		&i.Position,
		&i.EmploymentType,
		&i.JoinDate,
		&i.EndDate,
		&i.BasicSalary,
		&i.Allowance,
		&i.Phone,
		&i.Email,
		&i.Address,
		&i.City,
		&i.BankName,
		&i.BankAccount,
		&i.BankAccountName,
		&i.Npwp,
		&i.BpjsKetenagakerjaanNo,
		&i.BpjsKesehatanNo,
		&i.Photo,
		&i.IsActive,
		&i.LeaveBalance,
		&i.LeaveUsed,
		&i.DeletedAt,
	)
	return i, err
}

const createLeave = `-- name: CreateLeave :one
INSERT INTO leaves (employee_id, leave_type, start_date, end_date, total_days,
       reason, status, approved_by, approved_at, notes)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)
RETURNING id, employee_id, leave_type, start_date::text, end_date::text, total_days, reason,
       status, approved_by, approved_at, notes
`

type CreateLeaveParams struct {
	EmployeeID int64              `json:"employee_id"`
	LeaveType  string             `json:"leave_type"`
	StartDate  pgtype.Date        `json:"start_date"`
	EndDate    pgtype.Date        `json:"end_date"`
	TotalDays  int32              `json:"total_days"`
	Reason     pgtype.Text        `json:"reason"`
	Status     string             `json:"status"`
	ApprovedBy pgtype.Int8        `json:"approved_by"`
	ApprovedAt pgtype.Timestamptz `json:"approved_at"`
	Notes      pgtype.Text        `json:"notes"`
}

type CreateLeaveRow struct {
	ID         int64              `json:"id"`
	EmployeeID int64              `json:"employee_id"`
	LeaveType  string             `json:"leave_type"`
	StartDate  string             `json:"start_date"`
	EndDate    string             `json:"end_date"`
	TotalDays  int32              `json:"total_days"`
	Reason     pgtype.Text        `json:"reason"`
	Status     string             `json:"status"`
	ApprovedBy pgtype.Int8        `json:"approved_by"`
	ApprovedAt pgtype.Timestamptz `json:"approved_at"`
	Notes      pgtype.Text        `json:"notes"`
}

func (q *Queries) CreateLeave(ctx context.Context, arg CreateLeaveParams) (CreateLeaveRow, error) {
	row := q.db.QueryRow(ctx, createLeave,
		arg.EmployeeID,
		arg.LeaveType,
		arg.StartDate,
		arg.EndDate,
		arg.TotalDays,
		arg.Reason,
		arg.Status,
		arg.ApprovedBy,
		arg.ApprovedAt,
		arg.Notes,
	)
	var i CreateLeaveRow
	err := row.Scan(
		&i.ID,
		&i.EmployeeID,
		&i.LeaveType,
		&i.StartDate,
		&i.EndDate,
		&i.TotalDays,
		&i.Reason,
		&i.Status,
		&i.ApprovedBy,
		&i.ApprovedAt,
		&i.Notes,
	)
	return i, err
}

const createPayroll = `-- name: CreatePayroll :one
INSERT INTO payrolls (payroll_number, employee_id, period_month, period_year, basic_salary,
       allowances, overtime_pay, bonus, deductions, bpjs_ketenagakerjaan, bpjs_kesehatan,
       pph21, net_salary, payment_date, status, notes)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16)
RETURNING id, payroll_number, employee_id, period_month, period_year, basic_salary,
       allowances, overtime_pay, bonus, deductions, bpjs_ketenagakerjaan, bpjs_kesehatan,
       pph21, net_salary, COALESCE(payment_date::text, '')::text AS payment_date, status, notes
`

type CreatePayrollParams struct {
	PayrollNumber       string          `json:"payroll_number"`
	EmployeeID          int64           `json:"employee_id"`
	PeriodMonth         int16           `json:"period_month"`
	PeriodYear          int16           `json:"period_year"`
	BasicSalary         decimal.Decimal `json:"basic_salary"`
	Allowances          decimal.Decimal `json:"allowances"`
	OvertimePay         decimal.Decimal `json:"overtime_pay"`
	Bonus               decimal.Decimal `json:"bonus"`
	Deductions          decimal.Decimal `json:"deductions"`
	BpjsKetenagakerjaan decimal.Decimal `json:"bpjs_ketenagakerjaan"`
	BpjsKesehatan       decimal.Decimal `json:"bpjs_kesehatan"`
	Pph21               decimal.Decimal `json:"pph21"`
	NetSalary           decimal.Decimal `json:"net_salary"`
	PaymentDate         pgtype.Date     `json:"payment_date"`
	Status              string          `json:"status"`
	Notes               pgtype.Text     `json:"notes"`
}

type CreatePayrollRow struct {
	ID                  int64           `json:"id"`
	PayrollNumber       string          `json:"payroll_number"`
	EmployeeID          int64           `json:"employee_id"`
	PeriodMonth         int16           `json:"period_month"`
	PeriodYear          int16           `json:"period_year"`
	BasicSalary         decimal.Decimal `json:"basic_salary"`
	Allowances          decimal.Decimal `json:"allowances"`
	OvertimePay         decimal.Decimal `json:"overtime_pay"`
	Bonus               decimal.Decimal `json:"bonus"`
	Deductions          decimal.Decimal `json:"deductions"`
	BpjsKetenagakerjaan decimal.Decimal `json:"bpjs_ketenagakerjaan"`
	BpjsKesehatan       decimal.Decimal `json:"bpjs_kesehatan"`
	Pph21               decimal.Decimal `json:"pph21"`
	NetSalary           decimal.Decimal `json:"net_salary"`
	PaymentDate         string          `json:"payment_date"`
	Status              string          `json:"status"`
	Notes               pgtype.Text     `json:"notes"`
}

func (q *Queries) CreatePayroll(ctx context.Context, arg CreatePayrollParams) (CreatePayrollRow, error) {
	row := q.db.QueryRow(ctx, createPayroll,
		arg.PayrollNumber,
		arg.EmployeeID,
		arg.PeriodMonth,
		arg.PeriodYear,
		arg.BasicSalary,
		arg.Allowances,
		arg.OvertimePay,
		arg.Bonus,
		arg.Deductions,
		arg.BpjsKetenagakerjaan,
		arg.BpjsKesehatan,
		arg.Pph21,
		arg.NetSalary,
		arg.PaymentDate,
		arg.Status,
		arg.Notes,
	)
	var i CreatePayrollRow
	err := row.Scan(
		&i.ID,
		&i.PayrollNumber,
		&i.EmployeeID,
		&i.PeriodMonth,
		&i.PeriodYear,
		&i.BasicSalary,
		&i.Allowances,
		&i.OvertimePay,
		&i.Bonus,
		&i.Deductions,
		&i.BpjsKetenagakerjaan,
		&i.BpjsKesehatan,
		&i.Pph21,
		&i.NetSalary,
		&i.PaymentDate,
		&i.Status,
		&i.Notes,
	)
	return i, err
}

const createPerformance = `-- name: CreatePerformance :one
INSERT INTO performances (employee_id, evaluator_id, period_month, period_year, kpi_score,
       attitude_score, teamwork_score, achievement_score, total_score, grade, achievements,
       improvements, notes)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13)
RETURNING id, employee_id, evaluator_id, period_month, period_year, kpi_score,
       attitude_score, teamwork_score, achievement_score, total_score, grade, achievements,
       improvements, notes
`

type CreatePerformanceParams struct {
	EmployeeID       int64               `json:"employee_id"`
	EvaluatorID      pgtype.Int8         `json:"evaluator_id"`
	PeriodMonth      int16               `json:"period_month"`
	PeriodYear       int16               `json:"period_year"`
	KpiScore         decimal.NullDecimal `json:"kpi_score"`
	AttitudeScore    decimal.NullDecimal `json:"attitude_score"`
	TeamworkScore    decimal.NullDecimal `json:"teamwork_score"`
	AchievementScore decimal.NullDecimal `json:"achievement_score"`
	TotalScore       decimal.NullDecimal `json:"total_score"`
	Grade            pgtype.Text         `json:"grade"`
	Achievements     pgtype.Text         `json:"achievements"`
	Improvements     pgtype.Text         `json:"improvements"`
	Notes            pgtype.Text         `json:"notes"`
}

type CreatePerformanceRow struct {
	ID               int64               `json:"id"`
	EmployeeID       int64               `json:"employee_id"`
	EvaluatorID      pgtype.Int8         `json:"evaluator_id"`
	PeriodMonth      int16               `json:"period_month"`
	PeriodYear       int16               `json:"period_year"`
	KpiScore         decimal.NullDecimal `json:"kpi_score"`
	AttitudeScore    decimal.NullDecimal `json:"attitude_score"`
	TeamworkScore    decimal.NullDecimal `json:"teamwork_score"`
	AchievementScore decimal.NullDecimal `json:"achievement_score"`
	TotalScore       decimal.NullDecimal `json:"total_score"`
	Grade            pgtype.Text         `json:"grade"`
	Achievements     pgtype.Text         `json:"achievements"`
	Improvements     pgtype.Text         `json:"improvements"`
	Notes            pgtype.Text         `json:"notes"`
}

func (q *Queries) CreatePerformance(ctx context.Context, arg CreatePerformanceParams) (CreatePerformanceRow, error) {
	row := q.db.QueryRow(ctx, createPerformance,
		arg.EmployeeID,
		arg.EvaluatorID,
		arg.PeriodMonth,
		arg.PeriodYear,
		arg.KpiScore,
		arg.AttitudeScore,
		arg.TeamworkScore,
		arg.AchievementScore,
		arg.TotalScore,
		arg.Grade,
		arg.Achievements,
		arg.Improvements,
		arg.Notes,
	)
	var i CreatePerformanceRow
	err := row.Scan(
		&i.ID,
		&i.EmployeeID,
		&i.EvaluatorID,
		&i.PeriodMonth,
		&i.PeriodYear,
		&i.KpiScore,
		&i.AttitudeScore,
		&i.TeamworkScore,
		&i.AchievementScore,
		&i.TotalScore,
		&i.Grade,
		&i.Achievements,
		&i.Improvements,
		&i.Notes,
	)
	return i, err
}

const deductEmployeeLeave = `-- name: DeductEmployeeLeave :one
UPDATE employees
SET leave_balance = leave_balance - $2, leave_used = leave_used + $2, updated_at = now()
WHERE id=$1 AND leave_balance >= $2
RETURNING leave_balance
`

type DeductEmployeeLeaveParams struct {
	ID           int64           `json:"id"`
	LeaveBalance decimal.Decimal `json:"leave_balance"`
}

func (q *Queries) DeductEmployeeLeave(ctx context.Context, arg DeductEmployeeLeaveParams) (decimal.Decimal, error) {
	row := q.db.QueryRow(ctx, deductEmployeeLeave, arg.ID, arg.LeaveBalance)
	var leave_balance decimal.Decimal
	err := row.Scan(&leave_balance)
	return leave_balance, err
}

const deletePerformance = `-- name: DeletePerformance :execrows
DELETE FROM performances WHERE id=$1
`

func (q *Queries) DeletePerformance(ctx context.Context, id int64) (int64, error) {
	result, err := q.db.Exec(ctx, deletePerformance, id)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const getAttendanceByID = `-- name: GetAttendanceByID :one
SELECT id, employee_id, attendance_date::text, clock_in, clock_out,
       clock_in_lat, clock_in_lng, clock_out_lat, clock_out_lng, status, work_hours,
       overtime_hours, notes
FROM attendances WHERE id=$1
`

type GetAttendanceByIDRow struct {
	ID             int64               `json:"id"`
	EmployeeID     int64               `json:"employee_id"`
	AttendanceDate string              `json:"attendance_date"`
	ClockIn        pgtype.Timestamptz  `json:"clock_in"`
	ClockOut       pgtype.Timestamptz  `json:"clock_out"`
	ClockInLat     decimal.NullDecimal `json:"clock_in_lat"`
	ClockInLng     decimal.NullDecimal `json:"clock_in_lng"`
	ClockOutLat    decimal.NullDecimal `json:"clock_out_lat"`
	ClockOutLng    decimal.NullDecimal `json:"clock_out_lng"`
	Status         string              `json:"status"`
	WorkHours      decimal.NullDecimal `json:"work_hours"`
	OvertimeHours  decimal.NullDecimal `json:"overtime_hours"`
	Notes          pgtype.Text         `json:"notes"`
}

func (q *Queries) GetAttendanceByID(ctx context.Context, id int64) (GetAttendanceByIDRow, error) {
	row := q.db.QueryRow(ctx, getAttendanceByID, id)
	var i GetAttendanceByIDRow
	err := row.Scan(
		&i.ID,
		&i.EmployeeID,
		&i.AttendanceDate,
		&i.ClockIn,
		&i.ClockOut,
		&i.ClockInLat,
		&i.ClockInLng,
		&i.ClockOutLat,
		&i.ClockOutLng,
		&i.Status,
		&i.WorkHours,
		&i.OvertimeHours,
		&i.Notes,
	)
	return i, err
}

const getAttendanceForDay = `-- name: GetAttendanceForDay :one
SELECT id, employee_id, attendance_date::text, clock_in, clock_out,
       clock_in_lat, clock_in_lng, clock_out_lat, clock_out_lng, status, work_hours,
       overtime_hours, notes
FROM attendances WHERE employee_id=$1 AND attendance_date=$2
`

type GetAttendanceForDayParams struct {
	EmployeeID     int64       `json:"employee_id"`
	AttendanceDate pgtype.Date `json:"attendance_date"`
}

type GetAttendanceForDayRow struct {
	ID             int64               `json:"id"`
	EmployeeID     int64               `json:"employee_id"`
	AttendanceDate string              `json:"attendance_date"`
	ClockIn        pgtype.Timestamptz  `json:"clock_in"`
	ClockOut       pgtype.Timestamptz  `json:"clock_out"`
	ClockInLat     decimal.NullDecimal `json:"clock_in_lat"`
	ClockInLng     decimal.NullDecimal `json:"clock_in_lng"`
	ClockOutLat    decimal.NullDecimal `json:"clock_out_lat"`
	ClockOutLng    decimal.NullDecimal `json:"clock_out_lng"`
	Status         string              `json:"status"`
	WorkHours      decimal.NullDecimal `json:"work_hours"`
	OvertimeHours  decimal.NullDecimal `json:"overtime_hours"`
	Notes          pgtype.Text         `json:"notes"`
}

func (q *Queries) GetAttendanceForDay(ctx context.Context, arg GetAttendanceForDayParams) (GetAttendanceForDayRow, error) {
	row := q.db.QueryRow(ctx, getAttendanceForDay, arg.EmployeeID, arg.AttendanceDate)
	var i GetAttendanceForDayRow
	err := row.Scan(
		&i.ID,
		&i.EmployeeID,
		&i.AttendanceDate,
		&i.ClockIn,
		&i.ClockOut,
		&i.ClockInLat,
		&i.ClockInLng,
		&i.ClockOutLat,
		&i.ClockOutLng,
		&i.Status,
		&i.WorkHours,
		&i.OvertimeHours,
		&i.Notes,
	)
	return i, err
}

const getEmployeeByID = `-- name: GetEmployeeByID :one
SELECT id, employee_number, user_id, name, nik, department, job_level, position,
       employment_type, join_date, end_date, basic_salary, allowance, phone, email, address, city,
       bank_name, bank_account, bank_account_name, npwp, bpjs_ketenagakerjaan_no, bpjs_kesehatan_no,
       photo, is_active, leave_balance, leave_used, deleted_at
FROM employees WHERE id=$1 AND deleted_at IS NULL
`

type GetEmployeeByIDRow struct {
	ID                    int64              `json:"id"`
	EmployeeNumber        string             `json:"employee_number"`
	UserID                pgtype.Int8        `json:"user_id"`
	Name                  string             `json:"name"`
	Nik                   pgtype.Text        `json:"nik"`
	Department            string             `json:"department"`
	JobLevel              string             `json:"job_level"`
	Position              pgtype.Text        `json:"position"`
	EmploymentType        string             `json:"employment_type"`
	JoinDate              pgtype.Date        `json:"join_date"`
	EndDate               pgtype.Date        `json:"end_date"`
	BasicSalary           decimal.Decimal    `json:"basic_salary"`
	Allowance             decimal.Decimal    `json:"allowance"`
	Phone                 pgtype.Text        `json:"phone"`
	Email                 pgtype.Text        `json:"email"`
	Address               pgtype.Text        `json:"address"`
	City                  pgtype.Text        `json:"city"`
	BankName              pgtype.Text        `json:"bank_name"`
	BankAccount           pgtype.Text        `json:"bank_account"`
	BankAccountName       pgtype.Text        `json:"bank_account_name"`
	Npwp                  pgtype.Text        `json:"npwp"`
	BpjsKetenagakerjaanNo pgtype.Text        `json:"bpjs_ketenagakerjaan_no"`
	BpjsKesehatanNo       pgtype.Text        `json:"bpjs_kesehatan_no"`
	Photo                 pgtype.Text        `json:"photo"`
	IsActive              bool               `json:"is_active"`
	LeaveBalance          decimal.Decimal    `json:"leave_balance"`
	LeaveUsed             decimal.Decimal    `json:"leave_used"`
	DeletedAt             pgtype.Timestamptz `json:"deleted_at"`
}

func (q *Queries) GetEmployeeByID(ctx context.Context, id int64) (GetEmployeeByIDRow, error) {
	row := q.db.QueryRow(ctx, getEmployeeByID, id)
	var i GetEmployeeByIDRow
	err := row.Scan(
		&i.ID,
		&i.EmployeeNumber,
		&i.UserID,
		&i.Name,
		&i.Nik,
		&i.Department,
		&i.JobLevel,
		&i.Position,
		&i.EmploymentType,
		&i.JoinDate,
		&i.EndDate,
		&i.BasicSalary,
		&i.Allowance,
		&i.Phone,
		&i.Email,
		&i.Address,
		&i.City,
		&i.BankName,
		&i.BankAccount,
		&i.BankAccountName,
		&i.Npwp,
		&i.BpjsKetenagakerjaanNo,
		&i.BpjsKesehatanNo,
		&i.Photo,
		&i.IsActive,
		&i.LeaveBalance,
		&i.LeaveUsed,
		&i.DeletedAt,
	)
	return i, err
}

const getEmployeeByUserID = `-- name: GetEmployeeByUserID :one
SELECT id, employee_number, user_id, name, nik, department, job_level, position,
       employment_type, join_date, end_date, basic_salary, allowance, phone, email, address, city,
       bank_name, bank_account, bank_account_name, npwp, bpjs_ketenagakerjaan_no, bpjs_kesehatan_no,
       photo, is_active, leave_balance, leave_used, deleted_at
FROM employees WHERE user_id=$1 AND deleted_at IS NULL
`

type GetEmployeeByUserIDRow struct {
	ID                    int64              `json:"id"`
	EmployeeNumber        string             `json:"employee_number"`
	UserID                pgtype.Int8        `json:"user_id"`
	Name                  string             `json:"name"`
	Nik                   pgtype.Text        `json:"nik"`
	Department            string             `json:"department"`
	JobLevel              string             `json:"job_level"`
	Position              pgtype.Text        `json:"position"`
	EmploymentType        string             `json:"employment_type"`
	JoinDate              pgtype.Date        `json:"join_date"`
	EndDate               pgtype.Date        `json:"end_date"`
	BasicSalary           decimal.Decimal    `json:"basic_salary"`
	Allowance             decimal.Decimal    `json:"allowance"`
	Phone                 pgtype.Text        `json:"phone"`
	Email                 pgtype.Text        `json:"email"`
	Address               pgtype.Text        `json:"address"`
	City                  pgtype.Text        `json:"city"`
	BankName              pgtype.Text        `json:"bank_name"`
	BankAccount           pgtype.Text        `json:"bank_account"`
	BankAccountName       pgtype.Text        `json:"bank_account_name"`
	Npwp                  pgtype.Text        `json:"npwp"`
	BpjsKetenagakerjaanNo pgtype.Text        `json:"bpjs_ketenagakerjaan_no"`
	BpjsKesehatanNo       pgtype.Text        `json:"bpjs_kesehatan_no"`
	Photo                 pgtype.Text        `json:"photo"`
	IsActive              bool               `json:"is_active"`
	LeaveBalance          decimal.Decimal    `json:"leave_balance"`
	LeaveUsed             decimal.Decimal    `json:"leave_used"`
	DeletedAt             pgtype.Timestamptz `json:"deleted_at"`
}

func (q *Queries) GetEmployeeByUserID(ctx context.Context, userID pgtype.Int8) (GetEmployeeByUserIDRow, error) {
	row := q.db.QueryRow(ctx, getEmployeeByUserID, userID)
	var i GetEmployeeByUserIDRow
	err := row.Scan(
		&i.ID,
		&i.EmployeeNumber,
		&i.UserID,
		&i.Name,
		&i.Nik,
		&i.Department,
		&i.JobLevel,
		&i.Position,
		&i.EmploymentType,
		&i.JoinDate,
		&i.EndDate,
		&i.BasicSalary,
		&i.Allowance,
		&i.Phone,
		&i.Email,
		&i.Address,
		&i.City,
		&i.BankName,
		&i.BankAccount,
		&i.BankAccountName,
		&i.Npwp,
		&i.BpjsKetenagakerjaanNo,
		&i.BpjsKesehatanNo,
		&i.Photo,
		&i.IsActive,
		&i.LeaveBalance,
		&i.LeaveUsed,
		&i.DeletedAt,
	)
	return i, err
}

const getLatestEmployeeNumber = `-- name: GetLatestEmployeeNumber :one
SELECT COALESCE(employee_number, '') AS employee_number
FROM employees
ORDER BY id DESC
LIMIT 1
`

func (q *Queries) GetLatestEmployeeNumber(ctx context.Context) (string, error) {
	row := q.db.QueryRow(ctx, getLatestEmployeeNumber)
	var employee_number string
	err := row.Scan(&employee_number)
	return employee_number, err
}

const getLeaveByID = `-- name: GetLeaveByID :one
SELECT id, employee_id, leave_type, start_date::text, end_date::text, total_days, reason,
       status, approved_by, approved_at, notes
FROM leaves WHERE id=$1
`

type GetLeaveByIDRow struct {
	ID         int64              `json:"id"`
	EmployeeID int64              `json:"employee_id"`
	LeaveType  string             `json:"leave_type"`
	StartDate  string             `json:"start_date"`
	EndDate    string             `json:"end_date"`
	TotalDays  int32              `json:"total_days"`
	Reason     pgtype.Text        `json:"reason"`
	Status     string             `json:"status"`
	ApprovedBy pgtype.Int8        `json:"approved_by"`
	ApprovedAt pgtype.Timestamptz `json:"approved_at"`
	Notes      pgtype.Text        `json:"notes"`
}

func (q *Queries) GetLeaveByID(ctx context.Context, id int64) (GetLeaveByIDRow, error) {
	row := q.db.QueryRow(ctx, getLeaveByID, id)
	var i GetLeaveByIDRow
	err := row.Scan(
		&i.ID,
		&i.EmployeeID,
		&i.LeaveType,
		&i.StartDate,
		&i.EndDate,
		&i.TotalDays,
		&i.Reason,
		&i.Status,
		&i.ApprovedBy,
		&i.ApprovedAt,
		&i.Notes,
	)
	return i, err
}

const getPayrollByID = `-- name: GetPayrollByID :one
SELECT id, payroll_number, employee_id, period_month, period_year, basic_salary,
       allowances, overtime_pay, bonus, deductions, bpjs_ketenagakerjaan, bpjs_kesehatan,
       pph21, net_salary, COALESCE(payment_date::text, '')::text AS payment_date, status, notes
FROM payrolls WHERE id=$1
`

type GetPayrollByIDRow struct {
	ID                  int64           `json:"id"`
	PayrollNumber       string          `json:"payroll_number"`
	EmployeeID          int64           `json:"employee_id"`
	PeriodMonth         int16           `json:"period_month"`
	PeriodYear          int16           `json:"period_year"`
	BasicSalary         decimal.Decimal `json:"basic_salary"`
	Allowances          decimal.Decimal `json:"allowances"`
	OvertimePay         decimal.Decimal `json:"overtime_pay"`
	Bonus               decimal.Decimal `json:"bonus"`
	Deductions          decimal.Decimal `json:"deductions"`
	BpjsKetenagakerjaan decimal.Decimal `json:"bpjs_ketenagakerjaan"`
	BpjsKesehatan       decimal.Decimal `json:"bpjs_kesehatan"`
	Pph21               decimal.Decimal `json:"pph21"`
	NetSalary           decimal.Decimal `json:"net_salary"`
	PaymentDate         string          `json:"payment_date"`
	Status              string          `json:"status"`
	Notes               pgtype.Text     `json:"notes"`
}

func (q *Queries) GetPayrollByID(ctx context.Context, id int64) (GetPayrollByIDRow, error) {
	row := q.db.QueryRow(ctx, getPayrollByID, id)
	var i GetPayrollByIDRow
	err := row.Scan(
		&i.ID,
		&i.PayrollNumber,
		&i.EmployeeID,
		&i.PeriodMonth,
		&i.PeriodYear,
		&i.BasicSalary,
		&i.Allowances,
		&i.OvertimePay,
		&i.Bonus,
		&i.Deductions,
		&i.BpjsKetenagakerjaan,
		&i.BpjsKesehatan,
		&i.Pph21,
		&i.NetSalary,
		&i.PaymentDate,
		&i.Status,
		&i.Notes,
	)
	return i, err
}

const getPerformanceByID = `-- name: GetPerformanceByID :one
SELECT pf.id, pf.employee_id, pf.evaluator_id, pf.period_month, pf.period_year, pf.kpi_score,
       pf.attitude_score, pf.teamwork_score, pf.achievement_score, pf.total_score, pf.grade, pf.achievements,
       pf.improvements, pf.notes,
       COALESCE(e.name, '') AS employee_name, COALESCE(ev.name, '') AS evaluator_name
FROM performances pf
LEFT JOIN employees e ON e.id = pf.employee_id
LEFT JOIN employees ev ON ev.id = pf.evaluator_id
WHERE pf.id=$1
`

type GetPerformanceByIDRow struct {
	ID               int64               `json:"id"`
	EmployeeID       int64               `json:"employee_id"`
	EvaluatorID      pgtype.Int8         `json:"evaluator_id"`
	PeriodMonth      int16               `json:"period_month"`
	PeriodYear       int16               `json:"period_year"`
	KpiScore         decimal.NullDecimal `json:"kpi_score"`
	AttitudeScore    decimal.NullDecimal `json:"attitude_score"`
	TeamworkScore    decimal.NullDecimal `json:"teamwork_score"`
	AchievementScore decimal.NullDecimal `json:"achievement_score"`
	TotalScore       decimal.NullDecimal `json:"total_score"`
	Grade            pgtype.Text         `json:"grade"`
	Achievements     pgtype.Text         `json:"achievements"`
	Improvements     pgtype.Text         `json:"improvements"`
	Notes            pgtype.Text         `json:"notes"`
	EmployeeName     string              `json:"employee_name"`
	EvaluatorName    string              `json:"evaluator_name"`
}

func (q *Queries) GetPerformanceByID(ctx context.Context, id int64) (GetPerformanceByIDRow, error) {
	row := q.db.QueryRow(ctx, getPerformanceByID, id)
	var i GetPerformanceByIDRow
	err := row.Scan(
		&i.ID,
		&i.EmployeeID,
		&i.EvaluatorID,
		&i.PeriodMonth,
		&i.PeriodYear,
		&i.KpiScore,
		&i.AttitudeScore,
		&i.TeamworkScore,
		&i.AchievementScore,
		&i.TotalScore,
		&i.Grade,
		&i.Achievements,
		&i.Improvements,
		&i.Notes,
		&i.EmployeeName,
		&i.EvaluatorName,
	)
	return i, err
}

const listActiveEmployees = `-- name: ListActiveEmployees :many
SELECT id, employee_number, user_id, name, nik, department, job_level, position,
       employment_type, join_date, end_date, basic_salary, allowance, phone, email, address, city,
       bank_name, bank_account, bank_account_name, npwp, bpjs_ketenagakerjaan_no, bpjs_kesehatan_no,
       photo, is_active, leave_balance, leave_used, deleted_at
FROM employees WHERE is_active=true AND deleted_at IS NULL ORDER BY id
`

type ListActiveEmployeesRow struct {
	ID                    int64              `json:"id"`
	EmployeeNumber        string             `json:"employee_number"`
	UserID                pgtype.Int8        `json:"user_id"`
	Name                  string             `json:"name"`
	Nik                   pgtype.Text        `json:"nik"`
	Department            string             `json:"department"`
	JobLevel              string             `json:"job_level"`
	Position              pgtype.Text        `json:"position"`
	EmploymentType        string             `json:"employment_type"`
	JoinDate              pgtype.Date        `json:"join_date"`
	EndDate               pgtype.Date        `json:"end_date"`
	BasicSalary           decimal.Decimal    `json:"basic_salary"`
	Allowance             decimal.Decimal    `json:"allowance"`
	Phone                 pgtype.Text        `json:"phone"`
	Email                 pgtype.Text        `json:"email"`
	Address               pgtype.Text        `json:"address"`
	City                  pgtype.Text        `json:"city"`
	BankName              pgtype.Text        `json:"bank_name"`
	BankAccount           pgtype.Text        `json:"bank_account"`
	BankAccountName       pgtype.Text        `json:"bank_account_name"`
	Npwp                  pgtype.Text        `json:"npwp"`
	BpjsKetenagakerjaanNo pgtype.Text        `json:"bpjs_ketenagakerjaan_no"`
	BpjsKesehatanNo       pgtype.Text        `json:"bpjs_kesehatan_no"`
	Photo                 pgtype.Text        `json:"photo"`
	IsActive              bool               `json:"is_active"`
	LeaveBalance          decimal.Decimal    `json:"leave_balance"`
	LeaveUsed             decimal.Decimal    `json:"leave_used"`
	DeletedAt             pgtype.Timestamptz `json:"deleted_at"`
}

func (q *Queries) ListActiveEmployees(ctx context.Context) ([]ListActiveEmployeesRow, error) {
	rows, err := q.db.Query(ctx, listActiveEmployees)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListActiveEmployeesRow
	for rows.Next() {
		var i ListActiveEmployeesRow
		if err := rows.Scan(
			&i.ID,
			&i.EmployeeNumber,
			&i.UserID,
			&i.Name,
			&i.Nik,
			&i.Department,
			&i.JobLevel,
			&i.Position,
			&i.EmploymentType,
			&i.JoinDate,
			&i.EndDate,
			&i.BasicSalary,
			&i.Allowance,
			&i.Phone,
			&i.Email,
			&i.Address,
			&i.City,
			&i.BankName,
			&i.BankAccount,
			&i.BankAccountName,
			&i.Npwp,
			&i.BpjsKetenagakerjaanNo,
			&i.BpjsKesehatanNo,
			&i.Photo,
			&i.IsActive,
			&i.LeaveBalance,
			&i.LeaveUsed,
			&i.DeletedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listApprovedLeavesForEmployeePeriod = `-- name: ListApprovedLeavesForEmployeePeriod :many
SELECT l.id, l.employee_id, l.leave_type, l.start_date::text AS start_date, l.end_date::text AS end_date, l.total_days, l.status
FROM leaves l
WHERE l.employee_id = $1 AND l.status = 'approved' AND l.start_date <= $3 AND l.end_date >= $2
`

type ListApprovedLeavesForEmployeePeriodParams struct {
	EmployeeID int64       `json:"employee_id"`
	EndDate    pgtype.Date `json:"end_date"`
	StartDate  pgtype.Date `json:"start_date"`
}

type ListApprovedLeavesForEmployeePeriodRow struct {
	ID         int64  `json:"id"`
	EmployeeID int64  `json:"employee_id"`
	LeaveType  string `json:"leave_type"`
	StartDate  string `json:"start_date"`
	EndDate    string `json:"end_date"`
	TotalDays  int32  `json:"total_days"`
	Status     string `json:"status"`
}

func (q *Queries) ListApprovedLeavesForEmployeePeriod(ctx context.Context, arg ListApprovedLeavesForEmployeePeriodParams) ([]ListApprovedLeavesForEmployeePeriodRow, error) {
	rows, err := q.db.Query(ctx, listApprovedLeavesForEmployeePeriod, arg.EmployeeID, arg.EndDate, arg.StartDate)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListApprovedLeavesForEmployeePeriodRow
	for rows.Next() {
		var i ListApprovedLeavesForEmployeePeriodRow
		if err := rows.Scan(
			&i.ID,
			&i.EmployeeID,
			&i.LeaveType,
			&i.StartDate,
			&i.EndDate,
			&i.TotalDays,
			&i.Status,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listAttendance = `-- name: ListAttendance :many
SELECT a.id, a.employee_id, a.attendance_date::text AS attendance_date, a.clock_in, a.clock_out,
       a.clock_in_lat, a.clock_in_lng, a.clock_out_lat, a.clock_out_lng, a.status, a.work_hours,
       a.overtime_hours, a.notes,
       COALESCE(e.name, '') AS employee_name, COALESCE(e.department, '') AS department
FROM attendances a
LEFT JOIN employees e ON e.id = a.employee_id
WHERE ($3::bigint IS NULL OR a.employee_id = $3)
  AND ($4::text IS NULL OR a.status = $4)
  AND ($5::date IS NULL OR a.attendance_date >= $5)
  AND ($6::date IS NULL OR a.attendance_date <= $6)
ORDER BY a.attendance_date DESC, a.id DESC
LIMIT $1 OFFSET $2
`

type ListAttendanceParams struct {
	Limit      int32       `json:"limit"`
	Offset     int32       `json:"offset"`
	EmployeeID pgtype.Int8 `json:"employee_id"`
	Status     pgtype.Text `json:"status"`
	DateFrom   pgtype.Date `json:"date_from"`
	DateTo     pgtype.Date `json:"date_to"`
}

type ListAttendanceRow struct {
	ID             int64               `json:"id"`
	EmployeeID     int64               `json:"employee_id"`
	AttendanceDate string              `json:"attendance_date"`
	ClockIn        pgtype.Timestamptz  `json:"clock_in"`
	ClockOut       pgtype.Timestamptz  `json:"clock_out"`
	ClockInLat     decimal.NullDecimal `json:"clock_in_lat"`
	ClockInLng     decimal.NullDecimal `json:"clock_in_lng"`
	ClockOutLat    decimal.NullDecimal `json:"clock_out_lat"`
	ClockOutLng    decimal.NullDecimal `json:"clock_out_lng"`
	Status         string              `json:"status"`
	WorkHours      decimal.NullDecimal `json:"work_hours"`
	OvertimeHours  decimal.NullDecimal `json:"overtime_hours"`
	Notes          pgtype.Text         `json:"notes"`
	EmployeeName   string              `json:"employee_name"`
	Department     string              `json:"department"`
}

func (q *Queries) ListAttendance(ctx context.Context, arg ListAttendanceParams) ([]ListAttendanceRow, error) {
	rows, err := q.db.Query(ctx, listAttendance,
		arg.Limit,
		arg.Offset,
		arg.EmployeeID,
		arg.Status,
		arg.DateFrom,
		arg.DateTo,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListAttendanceRow
	for rows.Next() {
		var i ListAttendanceRow
		if err := rows.Scan(
			&i.ID,
			&i.EmployeeID,
			&i.AttendanceDate,
			&i.ClockIn,
			&i.ClockOut,
			&i.ClockInLat,
			&i.ClockInLng,
			&i.ClockOutLat,
			&i.ClockOutLng,
			&i.Status,
			&i.WorkHours,
			&i.OvertimeHours,
			&i.Notes,
			&i.EmployeeName,
			&i.Department,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listAttendanceForEmployeePeriod = `-- name: ListAttendanceForEmployeePeriod :many
SELECT a.id, a.employee_id, a.attendance_date::text AS attendance_date, a.status, a.work_hours, a.overtime_hours, a.notes
FROM attendances a
WHERE a.employee_id = $1 AND a.attendance_date >= $2 AND a.attendance_date <= $3
`

type ListAttendanceForEmployeePeriodParams struct {
	EmployeeID       int64       `json:"employee_id"`
	AttendanceDate   pgtype.Date `json:"attendance_date"`
	AttendanceDate_2 pgtype.Date `json:"attendance_date_2"`
}

type ListAttendanceForEmployeePeriodRow struct {
	ID             int64               `json:"id"`
	EmployeeID     int64               `json:"employee_id"`
	AttendanceDate string              `json:"attendance_date"`
	Status         string              `json:"status"`
	WorkHours      decimal.NullDecimal `json:"work_hours"`
	OvertimeHours  decimal.NullDecimal `json:"overtime_hours"`
	Notes          pgtype.Text         `json:"notes"`
}

func (q *Queries) ListAttendanceForEmployeePeriod(ctx context.Context, arg ListAttendanceForEmployeePeriodParams) ([]ListAttendanceForEmployeePeriodRow, error) {
	rows, err := q.db.Query(ctx, listAttendanceForEmployeePeriod, arg.EmployeeID, arg.AttendanceDate, arg.AttendanceDate_2)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListAttendanceForEmployeePeriodRow
	for rows.Next() {
		var i ListAttendanceForEmployeePeriodRow
		if err := rows.Scan(
			&i.ID,
			&i.EmployeeID,
			&i.AttendanceDate,
			&i.Status,
			&i.WorkHours,
			&i.OvertimeHours,
			&i.Notes,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listEmployees = `-- name: ListEmployees :many
SELECT id, employee_number, user_id, name, nik, department, job_level, position,
       employment_type, join_date, end_date, basic_salary, allowance, phone, email, address, city,
       bank_name, bank_account, bank_account_name, npwp, bpjs_ketenagakerjaan_no, bpjs_kesehatan_no,
       photo, is_active, leave_balance, leave_used, deleted_at
FROM employees
WHERE deleted_at IS NULL
  AND ($3::text IS NULL OR (name ILIKE '%' || $3 || '%' OR nik ILIKE '%' || $3 || '%' OR employee_number ILIKE '%' || $3 || '%'))
  AND ($4::boolean IS NULL OR is_active = $4)
ORDER BY
  CASE WHEN $5::text = 'name' AND $6::text <> 'desc' THEN name END ASC,
  CASE WHEN $5::text = 'name' AND $6::text = 'desc' THEN name END DESC,
  CASE WHEN $5::text = 'employee_number' AND $6::text <> 'desc' THEN employee_number END ASC,
  CASE WHEN $5::text = 'employee_number' AND $6::text = 'desc' THEN employee_number END DESC,
  CASE WHEN $5::text = 'department' AND $6::text <> 'desc' THEN department END ASC,
  CASE WHEN $5::text = 'department' AND $6::text = 'desc' THEN department END DESC,
  CASE WHEN $5::text = 'position' AND $6::text <> 'desc' THEN position END ASC,
  CASE WHEN $5::text = 'position' AND $6::text = 'desc' THEN position END DESC,
  CASE WHEN $5::text = 'join_date' AND $6::text <> 'desc' THEN join_date END ASC NULLS LAST,
  CASE WHEN $5::text = 'join_date' AND $6::text = 'desc' THEN join_date END DESC NULLS LAST,
  CASE WHEN $5::text = 'basic_salary' AND $6::text <> 'desc' THEN basic_salary END ASC NULLS LAST,
  CASE WHEN $5::text = 'basic_salary' AND $6::text = 'desc' THEN basic_salary END DESC NULLS LAST,
  CASE WHEN $5::text = 'leave_balance' AND $6::text <> 'desc' THEN leave_balance END ASC NULLS LAST,
  CASE WHEN $5::text = 'leave_balance' AND $6::text = 'desc' THEN leave_balance END DESC NULLS LAST,
  CASE WHEN $5::text = 'is_active' AND $6::text <> 'desc' THEN is_active END ASC NULLS LAST,
  CASE WHEN $5::text = 'is_active' AND $6::text = 'desc' THEN is_active END DESC NULLS LAST,
  employee_number
LIMIT $1 OFFSET $2
`

type ListEmployeesParams struct {
	Limit   int32       `json:"limit"`
	Offset  int32       `json:"offset"`
	Search  pgtype.Text `json:"search"`
	Active  pgtype.Bool `json:"active"`
	SortBy  pgtype.Text `json:"sort_by"`
	SortDir pgtype.Text `json:"sort_dir"`
}

type ListEmployeesRow struct {
	ID                    int64              `json:"id"`
	EmployeeNumber        string             `json:"employee_number"`
	UserID                pgtype.Int8        `json:"user_id"`
	Name                  string             `json:"name"`
	Nik                   pgtype.Text        `json:"nik"`
	Department            string             `json:"department"`
	JobLevel              string             `json:"job_level"`
	Position              pgtype.Text        `json:"position"`
	EmploymentType        string             `json:"employment_type"`
	JoinDate              pgtype.Date        `json:"join_date"`
	EndDate               pgtype.Date        `json:"end_date"`
	BasicSalary           decimal.Decimal    `json:"basic_salary"`
	Allowance             decimal.Decimal    `json:"allowance"`
	Phone                 pgtype.Text        `json:"phone"`
	Email                 pgtype.Text        `json:"email"`
	Address               pgtype.Text        `json:"address"`
	City                  pgtype.Text        `json:"city"`
	BankName              pgtype.Text        `json:"bank_name"`
	BankAccount           pgtype.Text        `json:"bank_account"`
	BankAccountName       pgtype.Text        `json:"bank_account_name"`
	Npwp                  pgtype.Text        `json:"npwp"`
	BpjsKetenagakerjaanNo pgtype.Text        `json:"bpjs_ketenagakerjaan_no"`
	BpjsKesehatanNo       pgtype.Text        `json:"bpjs_kesehatan_no"`
	Photo                 pgtype.Text        `json:"photo"`
	IsActive              bool               `json:"is_active"`
	LeaveBalance          decimal.Decimal    `json:"leave_balance"`
	LeaveUsed             decimal.Decimal    `json:"leave_used"`
	DeletedAt             pgtype.Timestamptz `json:"deleted_at"`
}

// ERP column sort (sort_by + sort_dir), whitelist-gated and dir-gated like
// products (the un-gated ASC clause dominating its DESC twin is the products
// ORDER BY bug fixed 3 Nov). Default remains employee_number.
func (q *Queries) ListEmployees(ctx context.Context, arg ListEmployeesParams) ([]ListEmployeesRow, error) {
	rows, err := q.db.Query(ctx, listEmployees,
		arg.Limit,
		arg.Offset,
		arg.Search,
		arg.Active,
		arg.SortBy,
		arg.SortDir,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListEmployeesRow
	for rows.Next() {
		var i ListEmployeesRow
		if err := rows.Scan(
			&i.ID,
			&i.EmployeeNumber,
			&i.UserID,
			&i.Name,
			&i.Nik,
			&i.Department,
			&i.JobLevel,
			&i.Position,
			&i.EmploymentType,
			&i.JoinDate,
			&i.EndDate,
			&i.BasicSalary,
			&i.Allowance,
			&i.Phone,
			&i.Email,
			&i.Address,
			&i.City,
			&i.BankName,
			&i.BankAccount,
			&i.BankAccountName,
			&i.Npwp,
			&i.BpjsKetenagakerjaanNo,
			&i.BpjsKesehatanNo,
			&i.Photo,
			&i.IsActive,
			&i.LeaveBalance,
			&i.LeaveUsed,
			&i.DeletedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listLeaves = `-- name: ListLeaves :many
SELECT l.id, l.employee_id, l.leave_type, l.start_date::text AS start_date, l.end_date::text AS end_date, l.total_days, l.reason,
       l.status, l.approved_by, l.approved_at, l.notes,
       COALESCE(e.name, '') AS employee_name
FROM leaves l
LEFT JOIN employees e ON e.id = l.employee_id
WHERE ($3::bigint IS NULL OR l.employee_id = $3)
  AND ($4::text IS NULL OR l.status = $4)
  AND ($5::date IS NULL OR l.start_date >= $5)
  AND ($6::date IS NULL OR l.start_date <= $6)
ORDER BY l.start_date DESC, l.id DESC
LIMIT $1 OFFSET $2
`

type ListLeavesParams struct {
	Limit      int32       `json:"limit"`
	Offset     int32       `json:"offset"`
	EmployeeID pgtype.Int8 `json:"employee_id"`
	Status     pgtype.Text `json:"status"`
	DateFrom   pgtype.Date `json:"date_from"`
	DateTo     pgtype.Date `json:"date_to"`
}

type ListLeavesRow struct {
	ID           int64              `json:"id"`
	EmployeeID   int64              `json:"employee_id"`
	LeaveType    string             `json:"leave_type"`
	StartDate    string             `json:"start_date"`
	EndDate      string             `json:"end_date"`
	TotalDays    int32              `json:"total_days"`
	Reason       pgtype.Text        `json:"reason"`
	Status       string             `json:"status"`
	ApprovedBy   pgtype.Int8        `json:"approved_by"`
	ApprovedAt   pgtype.Timestamptz `json:"approved_at"`
	Notes        pgtype.Text        `json:"notes"`
	EmployeeName string             `json:"employee_name"`
}

func (q *Queries) ListLeaves(ctx context.Context, arg ListLeavesParams) ([]ListLeavesRow, error) {
	rows, err := q.db.Query(ctx, listLeaves,
		arg.Limit,
		arg.Offset,
		arg.EmployeeID,
		arg.Status,
		arg.DateFrom,
		arg.DateTo,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListLeavesRow
	for rows.Next() {
		var i ListLeavesRow
		if err := rows.Scan(
			&i.ID,
			&i.EmployeeID,
			&i.LeaveType,
			&i.StartDate,
			&i.EndDate,
			&i.TotalDays,
			&i.Reason,
			&i.Status,
			&i.ApprovedBy,
			&i.ApprovedAt,
			&i.Notes,
			&i.EmployeeName,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listPayrolls = `-- name: ListPayrolls :many
SELECT pr.id, pr.payroll_number, pr.employee_id, pr.period_month, pr.period_year, pr.basic_salary,
       pr.allowances, pr.overtime_pay, pr.bonus, pr.deductions, pr.bpjs_ketenagakerjaan, pr.bpjs_kesehatan,
       pr.pph21, pr.net_salary, COALESCE(pr.payment_date::text, '')::text AS payment_date, pr.status, pr.notes,
       COALESCE(e.name, '') AS employee_name,
       (pr.basic_salary + pr.allowances + pr.overtime_pay + pr.bonus)::numeric AS gross_salary
FROM payrolls pr
LEFT JOIN employees e ON e.id = pr.employee_id
WHERE ($3::bigint IS NULL OR pr.employee_id = $3)
  AND ($4::text IS NULL OR pr.status = $4)
ORDER BY pr.period_year DESC, pr.period_month DESC, pr.id DESC
LIMIT $1 OFFSET $2
`

type ListPayrollsParams struct {
	Limit      int32       `json:"limit"`
	Offset     int32       `json:"offset"`
	EmployeeID pgtype.Int8 `json:"employee_id"`
	Status     pgtype.Text `json:"status"`
}

type ListPayrollsRow struct {
	ID                  int64           `json:"id"`
	PayrollNumber       string          `json:"payroll_number"`
	EmployeeID          int64           `json:"employee_id"`
	PeriodMonth         int16           `json:"period_month"`
	PeriodYear          int16           `json:"period_year"`
	BasicSalary         decimal.Decimal `json:"basic_salary"`
	Allowances          decimal.Decimal `json:"allowances"`
	OvertimePay         decimal.Decimal `json:"overtime_pay"`
	Bonus               decimal.Decimal `json:"bonus"`
	Deductions          decimal.Decimal `json:"deductions"`
	BpjsKetenagakerjaan decimal.Decimal `json:"bpjs_ketenagakerjaan"`
	BpjsKesehatan       decimal.Decimal `json:"bpjs_kesehatan"`
	Pph21               decimal.Decimal `json:"pph21"`
	NetSalary           decimal.Decimal `json:"net_salary"`
	PaymentDate         string          `json:"payment_date"`
	Status              string          `json:"status"`
	Notes               pgtype.Text     `json:"notes"`
	EmployeeName        string          `json:"employee_name"`
	GrossSalary         decimal.Decimal `json:"gross_salary"`
}

func (q *Queries) ListPayrolls(ctx context.Context, arg ListPayrollsParams) ([]ListPayrollsRow, error) {
	rows, err := q.db.Query(ctx, listPayrolls,
		arg.Limit,
		arg.Offset,
		arg.EmployeeID,
		arg.Status,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListPayrollsRow
	for rows.Next() {
		var i ListPayrollsRow
		if err := rows.Scan(
			&i.ID,
			&i.PayrollNumber,
			&i.EmployeeID,
			&i.PeriodMonth,
			&i.PeriodYear,
			&i.BasicSalary,
			&i.Allowances,
			&i.OvertimePay,
			&i.Bonus,
			&i.Deductions,
			&i.BpjsKetenagakerjaan,
			&i.BpjsKesehatan,
			&i.Pph21,
			&i.NetSalary,
			&i.PaymentDate,
			&i.Status,
			&i.Notes,
			&i.EmployeeName,
			&i.GrossSalary,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listPerformances = `-- name: ListPerformances :many
SELECT pf.id, pf.employee_id, pf.evaluator_id, pf.period_month, pf.period_year, pf.kpi_score,
       pf.attitude_score, pf.teamwork_score, pf.achievement_score, pf.total_score, pf.grade, pf.achievements,
       pf.improvements, pf.notes,
       COALESCE(e.name, '') AS employee_name, COALESCE(ev.name, '') AS evaluator_name
FROM performances pf
LEFT JOIN employees e ON e.id = pf.employee_id
LEFT JOIN employees ev ON ev.id = pf.evaluator_id
ORDER BY pf.period_year DESC, pf.period_month DESC
LIMIT $1 OFFSET $2
`

type ListPerformancesParams struct {
	Limit  int32 `json:"limit"`
	Offset int32 `json:"offset"`
}

type ListPerformancesRow struct {
	ID               int64               `json:"id"`
	EmployeeID       int64               `json:"employee_id"`
	EvaluatorID      pgtype.Int8         `json:"evaluator_id"`
	PeriodMonth      int16               `json:"period_month"`
	PeriodYear       int16               `json:"period_year"`
	KpiScore         decimal.NullDecimal `json:"kpi_score"`
	AttitudeScore    decimal.NullDecimal `json:"attitude_score"`
	TeamworkScore    decimal.NullDecimal `json:"teamwork_score"`
	AchievementScore decimal.NullDecimal `json:"achievement_score"`
	TotalScore       decimal.NullDecimal `json:"total_score"`
	Grade            pgtype.Text         `json:"grade"`
	Achievements     pgtype.Text         `json:"achievements"`
	Improvements     pgtype.Text         `json:"improvements"`
	Notes            pgtype.Text         `json:"notes"`
	EmployeeName     string              `json:"employee_name"`
	EvaluatorName    string              `json:"evaluator_name"`
}

func (q *Queries) ListPerformances(ctx context.Context, arg ListPerformancesParams) ([]ListPerformancesRow, error) {
	rows, err := q.db.Query(ctx, listPerformances, arg.Limit, arg.Offset)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListPerformancesRow
	for rows.Next() {
		var i ListPerformancesRow
		if err := rows.Scan(
			&i.ID,
			&i.EmployeeID,
			&i.EvaluatorID,
			&i.PeriodMonth,
			&i.PeriodYear,
			&i.KpiScore,
			&i.AttitudeScore,
			&i.TeamworkScore,
			&i.AchievementScore,
			&i.TotalScore,
			&i.Grade,
			&i.Achievements,
			&i.Improvements,
			&i.Notes,
			&i.EmployeeName,
			&i.EvaluatorName,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const payPayroll = `-- name: PayPayroll :execrows
UPDATE payrolls SET status='paid', payment_date=$2, notes=$3, updated_at=now() WHERE id=$1
`

type PayPayrollParams struct {
	ID          int64       `json:"id"`
	PaymentDate pgtype.Date `json:"payment_date"`
	Notes       pgtype.Text `json:"notes"`
}

func (q *Queries) PayPayroll(ctx context.Context, arg PayPayrollParams) (int64, error) {
	result, err := q.db.Exec(ctx, payPayroll, arg.ID, arg.PaymentDate, arg.Notes)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const softDeleteEmployee = `-- name: SoftDeleteEmployee :execrows
UPDATE employees SET deleted_at=now() WHERE id=$1 AND deleted_at IS NULL
`

func (q *Queries) SoftDeleteEmployee(ctx context.Context, id int64) (int64, error) {
	result, err := q.db.Exec(ctx, softDeleteEmployee, id)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const updateAttendance = `-- name: UpdateAttendance :execrows
UPDATE attendances SET clock_in=$3, clock_out=$4, clock_in_lat=$5, clock_in_lng=$6,
       clock_out_lat=$7, clock_out_lng=$8, status=$9, work_hours=$10, overtime_hours=$11, notes=$12
WHERE id=$1 AND employee_id=$2
`

type UpdateAttendanceParams struct {
	ID            int64               `json:"id"`
	EmployeeID    int64               `json:"employee_id"`
	ClockIn       pgtype.Timestamptz  `json:"clock_in"`
	ClockOut      pgtype.Timestamptz  `json:"clock_out"`
	ClockInLat    decimal.NullDecimal `json:"clock_in_lat"`
	ClockInLng    decimal.NullDecimal `json:"clock_in_lng"`
	ClockOutLat   decimal.NullDecimal `json:"clock_out_lat"`
	ClockOutLng   decimal.NullDecimal `json:"clock_out_lng"`
	Status        string              `json:"status"`
	WorkHours     decimal.NullDecimal `json:"work_hours"`
	OvertimeHours decimal.NullDecimal `json:"overtime_hours"`
	Notes         pgtype.Text         `json:"notes"`
}

func (q *Queries) UpdateAttendance(ctx context.Context, arg UpdateAttendanceParams) (int64, error) {
	result, err := q.db.Exec(ctx, updateAttendance,
		arg.ID,
		arg.EmployeeID,
		arg.ClockIn,
		arg.ClockOut,
		arg.ClockInLat,
		arg.ClockInLng,
		arg.ClockOutLat,
		arg.ClockOutLng,
		arg.Status,
		arg.WorkHours,
		arg.OvertimeHours,
		arg.Notes,
	)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const updateEmployee = `-- name: UpdateEmployee :execrows
UPDATE employees SET user_id=$2, name=$3, nik=$4, department=$5, job_level=$6, position=$7,
       employment_type=$8, join_date=$9, end_date=$10, basic_salary=$11, allowance=$12, phone=$13,
       email=$14, address=$15, city=$16, bank_name=$17, bank_account=$18,
       bank_account_name=$19, npwp=$20, bpjs_ketenagakerjaan_no=$21, bpjs_kesehatan_no=$22, photo=$23, is_active=$24, updated_at=now()
WHERE id=$1 AND deleted_at IS NULL
`

type UpdateEmployeeParams struct {
	ID                    int64           `json:"id"`
	UserID                pgtype.Int8     `json:"user_id"`
	Name                  string          `json:"name"`
	Nik                   pgtype.Text     `json:"nik"`
	Department            string          `json:"department"`
	JobLevel              string          `json:"job_level"`
	Position              pgtype.Text     `json:"position"`
	EmploymentType        string          `json:"employment_type"`
	JoinDate              pgtype.Date     `json:"join_date"`
	EndDate               pgtype.Date     `json:"end_date"`
	BasicSalary           decimal.Decimal `json:"basic_salary"`
	Allowance             decimal.Decimal `json:"allowance"`
	Phone                 pgtype.Text     `json:"phone"`
	Email                 pgtype.Text     `json:"email"`
	Address               pgtype.Text     `json:"address"`
	City                  pgtype.Text     `json:"city"`
	BankName              pgtype.Text     `json:"bank_name"`
	BankAccount           pgtype.Text     `json:"bank_account"`
	BankAccountName       pgtype.Text     `json:"bank_account_name"`
	Npwp                  pgtype.Text     `json:"npwp"`
	BpjsKetenagakerjaanNo pgtype.Text     `json:"bpjs_ketenagakerjaan_no"`
	BpjsKesehatanNo       pgtype.Text     `json:"bpjs_kesehatan_no"`
	Photo                 pgtype.Text     `json:"photo"`
	IsActive              bool            `json:"is_active"`
}

func (q *Queries) UpdateEmployee(ctx context.Context, arg UpdateEmployeeParams) (int64, error) {
	result, err := q.db.Exec(ctx, updateEmployee,
		arg.ID,
		arg.UserID,
		arg.Name,
		arg.Nik,
		arg.Department,
		arg.JobLevel,
		arg.Position,
		arg.EmploymentType,
		arg.JoinDate,
		arg.EndDate,
		arg.BasicSalary,
		arg.Allowance,
		arg.Phone,
		arg.Email,
		arg.Address,
		arg.City,
		arg.BankName,
		arg.BankAccount,
		arg.BankAccountName,
		arg.Npwp,
		arg.BpjsKetenagakerjaanNo,
		arg.BpjsKesehatanNo,
		arg.Photo,
		arg.IsActive,
	)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const updateLeave = `-- name: UpdateLeave :execrows
UPDATE leaves SET status=$3, approved_by=$4, approved_at=$5, notes=$6
WHERE id=$1 AND employee_id=$2
`

type UpdateLeaveParams struct {
	ID         int64              `json:"id"`
	EmployeeID int64              `json:"employee_id"`
	Status     string             `json:"status"`
	ApprovedBy pgtype.Int8        `json:"approved_by"`
	ApprovedAt pgtype.Timestamptz `json:"approved_at"`
	Notes      pgtype.Text        `json:"notes"`
}

func (q *Queries) UpdateLeave(ctx context.Context, arg UpdateLeaveParams) (int64, error) {
	result, err := q.db.Exec(ctx, updateLeave,
		arg.ID,
		arg.EmployeeID,
		arg.Status,
		arg.ApprovedBy,
		arg.ApprovedAt,
		arg.Notes,
	)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const updatePayroll = `-- name: UpdatePayroll :execrows
UPDATE payrolls SET status=$3, notes=$4 WHERE id=$1 AND employee_id=$2
`

type UpdatePayrollParams struct {
	ID         int64       `json:"id"`
	EmployeeID int64       `json:"employee_id"`
	Status     string      `json:"status"`
	Notes      pgtype.Text `json:"notes"`
}

func (q *Queries) UpdatePayroll(ctx context.Context, arg UpdatePayrollParams) (int64, error) {
	result, err := q.db.Exec(ctx, updatePayroll,
		arg.ID,
		arg.EmployeeID,
		arg.Status,
		arg.Notes,
	)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const updatePerformance = `-- name: UpdatePerformance :execrows
UPDATE performances SET kpi_score=$2, attitude_score=$3, teamwork_score=$4, achievement_score=$5,
       total_score=$6, grade=$7, achievements=$8, improvements=$9, notes=$10, updated_at=now()
WHERE id=$1
`

type UpdatePerformanceParams struct {
	ID               int64               `json:"id"`
	KpiScore         decimal.NullDecimal `json:"kpi_score"`
	AttitudeScore    decimal.NullDecimal `json:"attitude_score"`
	TeamworkScore    decimal.NullDecimal `json:"teamwork_score"`
	AchievementScore decimal.NullDecimal `json:"achievement_score"`
	TotalScore       decimal.NullDecimal `json:"total_score"`
	Grade            pgtype.Text         `json:"grade"`
	Achievements     pgtype.Text         `json:"achievements"`
	Improvements     pgtype.Text         `json:"improvements"`
	Notes            pgtype.Text         `json:"notes"`
}

func (q *Queries) UpdatePerformance(ctx context.Context, arg UpdatePerformanceParams) (int64, error) {
	result, err := q.db.Exec(ctx, updatePerformance,
		arg.ID,
		arg.KpiScore,
		arg.AttitudeScore,
		arg.TeamworkScore,
		arg.AchievementScore,
		arg.TotalScore,
		arg.Grade,
		arg.Achievements,
		arg.Improvements,
		arg.Notes,
	)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected(), nil
}

const upsertLeaveAttendance = `-- name: UpsertLeaveAttendance :exec
INSERT INTO attendances (employee_id, attendance_date, status, work_hours, overtime_hours, notes)
VALUES ($1, $2, 'leave', 0, 0, $3)
ON CONFLICT (employee_id, attendance_date)
DO UPDATE SET status = 'leave', notes = EXCLUDED.notes, updated_at = now()
`

type UpsertLeaveAttendanceParams struct {
	EmployeeID     int64       `json:"employee_id"`
	AttendanceDate pgtype.Date `json:"attendance_date"`
	Notes          pgtype.Text `json:"notes"`
}

func (q *Queries) UpsertLeaveAttendance(ctx context.Context, arg UpsertLeaveAttendanceParams) error {
	_, err := q.db.Exec(ctx, upsertLeaveAttendance, arg.EmployeeID, arg.AttendanceDate, arg.Notes)
	return err
}

const upsertPayroll = `-- name: UpsertPayroll :one
INSERT INTO payrolls (payroll_number, employee_id, period_month, period_year, basic_salary,
       allowances, overtime_pay, bonus, deductions, bpjs_ketenagakerjaan, bpjs_kesehatan,
       pph21, net_salary, payment_date, status, notes)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16)
ON CONFLICT (employee_id, period_month, period_year)
DO UPDATE SET
  basic_salary = EXCLUDED.basic_salary,
  allowances = EXCLUDED.allowances,
  overtime_pay = EXCLUDED.overtime_pay,
  bonus = EXCLUDED.bonus,
  deductions = EXCLUDED.deductions,
  bpjs_ketenagakerjaan = EXCLUDED.bpjs_ketenagakerjaan,
  bpjs_kesehatan = EXCLUDED.bpjs_kesehatan,
  pph21 = EXCLUDED.pph21,
  net_salary = EXCLUDED.net_salary,
  notes = EXCLUDED.notes,
  updated_at = now()
WHERE payrolls.status = 'draft'
RETURNING id, payroll_number, employee_id, period_month, period_year, basic_salary,
       allowances, overtime_pay, bonus, deductions, bpjs_ketenagakerjaan, bpjs_kesehatan,
       pph21, net_salary, COALESCE(payment_date::text, '')::text AS payment_date, status, notes
`

type UpsertPayrollParams struct {
	PayrollNumber       string          `json:"payroll_number"`
	EmployeeID          int64           `json:"employee_id"`
	PeriodMonth         int16           `json:"period_month"`
	PeriodYear          int16           `json:"period_year"`
	BasicSalary         decimal.Decimal `json:"basic_salary"`
	Allowances          decimal.Decimal `json:"allowances"`
	OvertimePay         decimal.Decimal `json:"overtime_pay"`
	Bonus               decimal.Decimal `json:"bonus"`
	Deductions          decimal.Decimal `json:"deductions"`
	BpjsKetenagakerjaan decimal.Decimal `json:"bpjs_ketenagakerjaan"`
	BpjsKesehatan       decimal.Decimal `json:"bpjs_kesehatan"`
	Pph21               decimal.Decimal `json:"pph21"`
	NetSalary           decimal.Decimal `json:"net_salary"`
	PaymentDate         pgtype.Date     `json:"payment_date"`
	Status              string          `json:"status"`
	Notes               pgtype.Text     `json:"notes"`
}

type UpsertPayrollRow struct {
	ID                  int64           `json:"id"`
	PayrollNumber       string          `json:"payroll_number"`
	EmployeeID          int64           `json:"employee_id"`
	PeriodMonth         int16           `json:"period_month"`
	PeriodYear          int16           `json:"period_year"`
	BasicSalary         decimal.Decimal `json:"basic_salary"`
	Allowances          decimal.Decimal `json:"allowances"`
	OvertimePay         decimal.Decimal `json:"overtime_pay"`
	Bonus               decimal.Decimal `json:"bonus"`
	Deductions          decimal.Decimal `json:"deductions"`
	BpjsKetenagakerjaan decimal.Decimal `json:"bpjs_ketenagakerjaan"`
	BpjsKesehatan       decimal.Decimal `json:"bpjs_kesehatan"`
	Pph21               decimal.Decimal `json:"pph21"`
	NetSalary           decimal.Decimal `json:"net_salary"`
	PaymentDate         string          `json:"payment_date"`
	Status              string          `json:"status"`
	Notes               pgtype.Text     `json:"notes"`
}

func (q *Queries) UpsertPayroll(ctx context.Context, arg UpsertPayrollParams) (UpsertPayrollRow, error) {
	row := q.db.QueryRow(ctx, upsertPayroll,
		arg.PayrollNumber,
		arg.EmployeeID,
		arg.PeriodMonth,
		arg.PeriodYear,
		arg.BasicSalary,
		arg.Allowances,
		arg.OvertimePay,
		arg.Bonus,
		arg.Deductions,
		arg.BpjsKetenagakerjaan,
		arg.BpjsKesehatan,
		arg.Pph21,
		arg.NetSalary,
		arg.PaymentDate,
		arg.Status,
		arg.Notes,
	)
	var i UpsertPayrollRow
	err := row.Scan(
		&i.ID,
		&i.PayrollNumber,
		&i.EmployeeID,
		&i.PeriodMonth,
		&i.PeriodYear,
		&i.BasicSalary,
		&i.Allowances,
		&i.OvertimePay,
		&i.Bonus,
		&i.Deductions,
		&i.BpjsKetenagakerjaan,
		&i.BpjsKesehatan,
		&i.Pph21,
		&i.NetSalary,
		&i.PaymentDate,
		&i.Status,
		&i.Notes,
	)
	return i, err
}
