-- =============================================================
-- ARCHIVO: 45-hr.sql
-- DESCRIPCION: Sistema de Recursos Humanos (RRHH)
-- VERSION: 1.0.0
-- PROYECTO: ERP-Core
-- FECHA: 2026-01-26
-- MODULO: MGN-010 (RRHH Basico)
-- REFERENCIA: odoo-hr-analysis.md, hr-domain.md
-- =============================================================

-- =====================
-- SCHEMA: hr
-- =====================
CREATE SCHEMA IF NOT EXISTS hr;

-- =====================
-- ENUMS
-- =====================

-- Estado del empleado
DO $$ BEGIN
    CREATE TYPE hr.employee_status AS ENUM (
        'active',
        'inactive',
        'on_leave',
        'terminated'
    );
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

-- Tipo de contrato
DO $$ BEGIN
    CREATE TYPE hr.contract_type AS ENUM (
        'permanent',
        'temporary',
        'contractor',
        'internship',
        'part_time'
    );
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

-- Estado del contrato
DO $$ BEGIN
    CREATE TYPE hr.contract_status AS ENUM (
        'draft',
        'active',
        'expired',
        'terminated',
        'cancelled'
    );
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

-- Tipo de ausencia
DO $$ BEGIN
    CREATE TYPE hr.leave_type_category AS ENUM (
        'vacation',
        'sick',
        'personal',
        'maternity',
        'paternity',
        'bereavement',
        'unpaid',
        'other'
    );
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

-- Estado de ausencia
DO $$ BEGIN
    CREATE TYPE hr.leave_status AS ENUM (
        'draft',
        'submitted',
        'approved',
        'rejected',
        'cancelled'
    );
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

-- Tipo de asignacion
DO $$ BEGIN
    CREATE TYPE hr.allocation_type AS ENUM (
        'fixed',
        'accrual',
        'unlimited'
    );
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

-- =====================
-- TABLA: hr.departments
-- Departamentos organizacionales
-- =====================
CREATE TABLE IF NOT EXISTS hr.departments (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
    company_id UUID NOT NULL REFERENCES core.companies(id) ON DELETE CASCADE,

    -- Identificacion
    name VARCHAR(255) NOT NULL,
    code VARCHAR(50),

    -- Jerarquia
    parent_id UUID REFERENCES hr.departments(id) ON DELETE SET NULL,
    manager_id UUID, -- FK a employees (se agrega despues)

    -- Estado
    is_active BOOLEAN NOT NULL DEFAULT true,

    -- Metadata
    description TEXT,
    color VARCHAR(7),

    -- Audit
    created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,

    UNIQUE(tenant_id, company_id, code)
);

-- Indices
CREATE INDEX IF NOT EXISTS idx_departments_tenant ON hr.departments(tenant_id);
CREATE INDEX IF NOT EXISTS idx_departments_company ON hr.departments(company_id);
CREATE INDEX IF NOT EXISTS idx_departments_parent ON hr.departments(parent_id);
CREATE INDEX IF NOT EXISTS idx_departments_active ON hr.departments(is_active) WHERE is_active = true;

-- =====================
-- TABLA: hr.job_positions
-- Puestos de trabajo
-- =====================
CREATE TABLE IF NOT EXISTS hr.job_positions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
    company_id UUID NOT NULL REFERENCES core.companies(id) ON DELETE CASCADE,

    -- Identificacion
    name VARCHAR(255) NOT NULL,
    code VARCHAR(50),
    description TEXT,

    -- Relaciones
    department_id UUID REFERENCES hr.departments(id) ON DELETE SET NULL,

    -- Estado
    is_active BOOLEAN NOT NULL DEFAULT true,

    -- Audit
    created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,

    UNIQUE(tenant_id, company_id, code)
);

-- Indices
CREATE INDEX IF NOT EXISTS idx_job_positions_tenant ON hr.job_positions(tenant_id);
CREATE INDEX IF NOT EXISTS idx_job_positions_department ON hr.job_positions(department_id);
CREATE INDEX IF NOT EXISTS idx_job_positions_active ON hr.job_positions(is_active) WHERE is_active = true;

-- =====================
-- TABLA: hr.employees
-- Empleados
-- =====================
CREATE TABLE IF NOT EXISTS hr.employees (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
    company_id UUID NOT NULL REFERENCES core.companies(id) ON DELETE CASCADE,

    -- Identificacion
    employee_number VARCHAR(50) NOT NULL,
    first_name VARCHAR(100) NOT NULL,
    last_name VARCHAR(100) NOT NULL,
    full_name VARCHAR(255) GENERATED ALWAYS AS (first_name || ' ' || last_name) STORED,

    -- Relaciones con usuario y partner
    user_id UUID REFERENCES auth.users(id) ON DELETE SET NULL,
    partner_id UUID, -- REFERENCES partners.partners(id)

    -- Organizacion
    department_id UUID REFERENCES hr.departments(id) ON DELETE SET NULL,
    job_position_id UUID REFERENCES hr.job_positions(id) ON DELETE SET NULL,
    manager_id UUID REFERENCES hr.employees(id) ON DELETE SET NULL,

    -- Contacto laboral
    work_email VARCHAR(255),
    work_phone VARCHAR(50),
    work_mobile VARCHAR(50),
    work_location VARCHAR(255),

    -- Datos personales
    personal_email VARCHAR(255),
    personal_phone VARCHAR(50),
    birth_date DATE,
    gender VARCHAR(20),
    marital_status VARCHAR(20),

    -- Identificacion oficial
    identification_type VARCHAR(50),
    identification_number VARCHAR(100),
    tax_id VARCHAR(50), -- RFC en Mexico
    social_security_number VARCHAR(50), -- NSS/IMSS

    -- Direccion
    street VARCHAR(255),
    city VARCHAR(100),
    state VARCHAR(100),
    postal_code VARCHAR(20),
    country VARCHAR(100),

    -- Empleo
    hire_date DATE NOT NULL,
    termination_date DATE,
    status hr.employee_status NOT NULL DEFAULT 'active',

    -- Emergencia
    emergency_contact_name VARCHAR(255),
    emergency_contact_phone VARCHAR(50),
    emergency_contact_relationship VARCHAR(50),

    -- Metadata
    notes TEXT,
    avatar_url TEXT,

    -- Audit
    created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,

    UNIQUE(tenant_id, employee_number)
);

-- Indices
CREATE INDEX IF NOT EXISTS idx_employees_tenant ON hr.employees(tenant_id);
CREATE INDEX IF NOT EXISTS idx_employees_company ON hr.employees(company_id);
CREATE INDEX IF NOT EXISTS idx_employees_department ON hr.employees(department_id);
CREATE INDEX IF NOT EXISTS idx_employees_job ON hr.employees(job_position_id);
CREATE INDEX IF NOT EXISTS idx_employees_manager ON hr.employees(manager_id);
CREATE INDEX IF NOT EXISTS idx_employees_user ON hr.employees(user_id);
CREATE INDEX IF NOT EXISTS idx_employees_status ON hr.employees(status);
CREATE INDEX IF NOT EXISTS idx_employees_active ON hr.employees(status) WHERE status = 'active';
CREATE INDEX IF NOT EXISTS idx_employees_name ON hr.employees(full_name);

-- Agregar FK de manager_id en departments
ALTER TABLE hr.departments
    ADD CONSTRAINT fk_departments_manager
    FOREIGN KEY (manager_id) REFERENCES hr.employees(id) ON DELETE SET NULL;

-- =====================
-- TABLA: hr.contracts
-- Contratos laborales
-- =====================
CREATE TABLE IF NOT EXISTS hr.contracts (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
    company_id UUID NOT NULL REFERENCES core.companies(id) ON DELETE CASCADE,

    -- Relaciones
    employee_id UUID NOT NULL REFERENCES hr.employees(id) ON DELETE CASCADE,

    -- Identificacion
    name VARCHAR(255) NOT NULL,
    reference VARCHAR(50),

    -- Tipo y estado
    contract_type hr.contract_type NOT NULL DEFAULT 'permanent',
    status hr.contract_status NOT NULL DEFAULT 'draft',

    -- Vigencia
    date_start DATE NOT NULL,
    date_end DATE,

    -- Puesto y departamento al momento del contrato
    job_position_id UUID REFERENCES hr.job_positions(id) ON DELETE SET NULL,
    department_id UUID REFERENCES hr.departments(id) ON DELETE SET NULL,

    -- Compensacion
    wage DECIMAL(15,2) NOT NULL,
    wage_type VARCHAR(20) NOT NULL DEFAULT 'monthly' CHECK (wage_type IN ('hourly', 'daily', 'weekly', 'biweekly', 'monthly', 'annual')),
    currency VARCHAR(3) NOT NULL DEFAULT 'MXN',

    -- Jornada
    hours_per_week DECIMAL(5,2) DEFAULT 48,
    schedule_type VARCHAR(50),

    -- Probatorio
    trial_period_months INTEGER DEFAULT 0,
    trial_date_end DATE,

    -- Metadata
    notes TEXT,
    document_url TEXT,

    -- Audit
    created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
    activated_at TIMESTAMPTZ,
    terminated_at TIMESTAMPTZ,
    terminated_by UUID REFERENCES auth.users(id),
    termination_reason TEXT
);

-- Indices
CREATE INDEX IF NOT EXISTS idx_contracts_tenant ON hr.contracts(tenant_id);
CREATE INDEX IF NOT EXISTS idx_contracts_employee ON hr.contracts(employee_id);
CREATE INDEX IF NOT EXISTS idx_contracts_status ON hr.contracts(status);
CREATE INDEX IF NOT EXISTS idx_contracts_active ON hr.contracts(employee_id, status) WHERE status = 'active';
CREATE INDEX IF NOT EXISTS idx_contracts_dates ON hr.contracts(date_start, date_end);

-- =====================
-- TABLA: hr.leave_types
-- Tipos de ausencia
-- =====================
CREATE TABLE IF NOT EXISTS hr.leave_types (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
    company_id UUID NOT NULL REFERENCES core.companies(id) ON DELETE CASCADE,

    -- Identificacion
    name VARCHAR(255) NOT NULL,
    code VARCHAR(50) NOT NULL,
    description TEXT,
    color VARCHAR(7) DEFAULT '#3B82F6',

    -- Categoria
    leave_category hr.leave_type_category NOT NULL DEFAULT 'other',

    -- Configuracion
    allocation_type hr.allocation_type NOT NULL DEFAULT 'fixed',
    requires_approval BOOLEAN NOT NULL DEFAULT true,
    requires_document BOOLEAN NOT NULL DEFAULT false,

    -- Limites
    max_days_per_request INTEGER,
    max_days_per_year INTEGER,
    min_days_notice INTEGER DEFAULT 0,

    -- Pago
    is_paid BOOLEAN NOT NULL DEFAULT true,
    pay_percentage DECIMAL(5,2) DEFAULT 100,

    -- Estado
    is_active BOOLEAN NOT NULL DEFAULT true,

    -- Audit
    created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,

    UNIQUE(tenant_id, company_id, code)
);

-- Indices
CREATE INDEX IF NOT EXISTS idx_leave_types_tenant ON hr.leave_types(tenant_id);
CREATE INDEX IF NOT EXISTS idx_leave_types_company ON hr.leave_types(company_id);
CREATE INDEX IF NOT EXISTS idx_leave_types_category ON hr.leave_types(leave_category);
CREATE INDEX IF NOT EXISTS idx_leave_types_active ON hr.leave_types(is_active) WHERE is_active = true;

-- =====================
-- TABLA: hr.leave_allocations
-- Asignacion de dias por empleado
-- =====================
CREATE TABLE IF NOT EXISTS hr.leave_allocations (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

    -- Relaciones
    employee_id UUID NOT NULL REFERENCES hr.employees(id) ON DELETE CASCADE,
    leave_type_id UUID NOT NULL REFERENCES hr.leave_types(id) ON DELETE CASCADE,

    -- Asignacion
    days_allocated DECIMAL(5,2) NOT NULL,
    days_used DECIMAL(5,2) NOT NULL DEFAULT 0,
    days_remaining DECIMAL(5,2) GENERATED ALWAYS AS (days_allocated - days_used) STORED,

    -- Periodo
    date_from DATE NOT NULL,
    date_to DATE NOT NULL,

    -- Metadata
    notes TEXT,

    -- Audit
    created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CHECK (date_to > date_from),
    CHECK (days_allocated >= 0),
    CHECK (days_used >= 0)
);

-- Indices
CREATE INDEX IF NOT EXISTS idx_leave_allocations_tenant ON hr.leave_allocations(tenant_id);
CREATE INDEX IF NOT EXISTS idx_leave_allocations_employee ON hr.leave_allocations(employee_id);
CREATE INDEX IF NOT EXISTS idx_leave_allocations_type ON hr.leave_allocations(leave_type_id);
CREATE INDEX IF NOT EXISTS idx_leave_allocations_period ON hr.leave_allocations(date_from, date_to);

-- =====================
-- TABLA: hr.leaves
-- Solicitudes de ausencia
-- =====================
CREATE TABLE IF NOT EXISTS hr.leaves (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
    company_id UUID NOT NULL REFERENCES core.companies(id) ON DELETE CASCADE,

    -- Relaciones
    employee_id UUID NOT NULL REFERENCES hr.employees(id) ON DELETE CASCADE,
    leave_type_id UUID NOT NULL REFERENCES hr.leave_types(id) ON DELETE RESTRICT,
    allocation_id UUID REFERENCES hr.leave_allocations(id) ON DELETE SET NULL,

    -- Periodo solicitado
    date_from DATE NOT NULL,
    date_to DATE NOT NULL,
    days_requested DECIMAL(5,2) NOT NULL,

    -- Si es parcial
    is_half_day BOOLEAN NOT NULL DEFAULT false,
    half_day_type VARCHAR(20) CHECK (half_day_type IN ('morning', 'afternoon')),

    -- Estado
    status hr.leave_status NOT NULL DEFAULT 'draft',

    -- Aprobacion
    approver_id UUID REFERENCES auth.users(id),
    approved_at TIMESTAMPTZ,
    rejection_reason TEXT,

    -- Metadata
    request_reason TEXT,
    document_url TEXT,
    notes TEXT,

    -- Audit
    created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
    submitted_at TIMESTAMPTZ,
    cancelled_at TIMESTAMPTZ,
    cancelled_by UUID REFERENCES auth.users(id),

    CHECK (date_to >= date_from),
    CHECK (days_requested > 0)
);

-- Indices
CREATE INDEX IF NOT EXISTS idx_leaves_tenant ON hr.leaves(tenant_id);
CREATE INDEX IF NOT EXISTS idx_leaves_company ON hr.leaves(company_id);
CREATE INDEX IF NOT EXISTS idx_leaves_employee ON hr.leaves(employee_id);
CREATE INDEX IF NOT EXISTS idx_leaves_type ON hr.leaves(leave_type_id);
CREATE INDEX IF NOT EXISTS idx_leaves_status ON hr.leaves(status);
CREATE INDEX IF NOT EXISTS idx_leaves_dates ON hr.leaves(date_from, date_to);
CREATE INDEX IF NOT EXISTS idx_leaves_pending ON hr.leaves(status) WHERE status IN ('submitted');
CREATE INDEX IF NOT EXISTS idx_leaves_approver ON hr.leaves(approver_id) WHERE status = 'submitted';

-- =====================
-- RLS POLICIES
-- =====================

-- Departments
ALTER TABLE hr.departments ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS tenant_isolation_departments ON hr.departments;
CREATE POLICY tenant_isolation_departments ON hr.departments
    FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- Job Positions
ALTER TABLE hr.job_positions ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS tenant_isolation_job_positions ON hr.job_positions;
CREATE POLICY tenant_isolation_job_positions ON hr.job_positions
    FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- Employees
ALTER TABLE hr.employees ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS tenant_isolation_employees ON hr.employees;
CREATE POLICY tenant_isolation_employees ON hr.employees
    FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- Contracts
ALTER TABLE hr.contracts ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS tenant_isolation_contracts ON hr.contracts;
CREATE POLICY tenant_isolation_contracts ON hr.contracts
    FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- Leave Types
ALTER TABLE hr.leave_types ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS tenant_isolation_leave_types ON hr.leave_types;
CREATE POLICY tenant_isolation_leave_types ON hr.leave_types
    FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- Leave Allocations
ALTER TABLE hr.leave_allocations ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS tenant_isolation_leave_allocations ON hr.leave_allocations;
CREATE POLICY tenant_isolation_leave_allocations ON hr.leave_allocations
    FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- Leaves
ALTER TABLE hr.leaves ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS tenant_isolation_leaves ON hr.leaves;
CREATE POLICY tenant_isolation_leaves ON hr.leaves
    FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- =====================
-- TRIGGERS
-- =====================

CREATE OR REPLACE FUNCTION hr.update_timestamp()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_departments_updated_at
    BEFORE UPDATE ON hr.departments
    FOR EACH ROW EXECUTE FUNCTION hr.update_timestamp();

CREATE TRIGGER trg_job_positions_updated_at
    BEFORE UPDATE ON hr.job_positions
    FOR EACH ROW EXECUTE FUNCTION hr.update_timestamp();

CREATE TRIGGER trg_employees_updated_at
    BEFORE UPDATE ON hr.employees
    FOR EACH ROW EXECUTE FUNCTION hr.update_timestamp();

CREATE TRIGGER trg_contracts_updated_at
    BEFORE UPDATE ON hr.contracts
    FOR EACH ROW EXECUTE FUNCTION hr.update_timestamp();

CREATE TRIGGER trg_leave_types_updated_at
    BEFORE UPDATE ON hr.leave_types
    FOR EACH ROW EXECUTE FUNCTION hr.update_timestamp();

CREATE TRIGGER trg_leave_allocations_updated_at
    BEFORE UPDATE ON hr.leave_allocations
    FOR EACH ROW EXECUTE FUNCTION hr.update_timestamp();

CREATE TRIGGER trg_leaves_updated_at
    BEFORE UPDATE ON hr.leaves
    FOR EACH ROW EXECUTE FUNCTION hr.update_timestamp();

-- =====================
-- FUNCIONES DE UTILIDAD
-- =====================

-- Obtener subordinados directos de un manager
CREATE OR REPLACE FUNCTION hr.get_direct_subordinates(p_manager_id UUID)
RETURNS TABLE (
    id UUID,
    employee_number VARCHAR(50),
    full_name VARCHAR(255),
    department_name VARCHAR(255),
    job_title VARCHAR(255)
) AS $$
BEGIN
    RETURN QUERY
    SELECT e.id, e.employee_number, e.full_name, d.name, j.name
    FROM hr.employees e
    LEFT JOIN hr.departments d ON d.id = e.department_id
    LEFT JOIN hr.job_positions j ON j.id = e.job_position_id
    WHERE e.manager_id = p_manager_id
    AND e.status = 'active'
    ORDER BY e.full_name;
END;
$$ LANGUAGE plpgsql STABLE;

-- Obtener saldo de dias de un tipo de ausencia
CREATE OR REPLACE FUNCTION hr.get_leave_balance(
    p_employee_id UUID,
    p_leave_type_id UUID,
    p_date DATE DEFAULT CURRENT_DATE
)
RETURNS TABLE (
    days_allocated DECIMAL(5,2),
    days_used DECIMAL(5,2),
    days_remaining DECIMAL(5,2)
) AS $$
BEGIN
    RETURN QUERY
    SELECT
        COALESCE(SUM(la.days_allocated), 0),
        COALESCE(SUM(la.days_used), 0),
        COALESCE(SUM(la.days_remaining), 0)
    FROM hr.leave_allocations la
    WHERE la.employee_id = p_employee_id
    AND la.leave_type_id = p_leave_type_id
    AND p_date BETWEEN la.date_from AND la.date_to;
END;
$$ LANGUAGE plpgsql STABLE;

-- Obtener contrato activo de un empleado
CREATE OR REPLACE FUNCTION hr.get_active_contract(p_employee_id UUID)
RETURNS hr.contracts AS $$
DECLARE
    v_contract hr.contracts;
BEGIN
    SELECT * INTO v_contract
    FROM hr.contracts
    WHERE employee_id = p_employee_id
    AND status = 'active'
    LIMIT 1;

    RETURN v_contract;
END;
$$ LANGUAGE plpgsql STABLE;

-- Verificar si hay solapamiento de ausencias
CREATE OR REPLACE FUNCTION hr.check_leave_overlap(
    p_employee_id UUID,
    p_date_from DATE,
    p_date_to DATE,
    p_exclude_leave_id UUID DEFAULT NULL
)
RETURNS BOOLEAN AS $$
DECLARE
    v_overlap_count INTEGER;
BEGIN
    SELECT COUNT(*) INTO v_overlap_count
    FROM hr.leaves l
    WHERE l.employee_id = p_employee_id
    AND l.status IN ('submitted', 'approved')
    AND l.date_from <= p_date_to
    AND l.date_to >= p_date_from
    AND (p_exclude_leave_id IS NULL OR l.id != p_exclude_leave_id);

    RETURN v_overlap_count > 0;
END;
$$ LANGUAGE plpgsql STABLE;

-- =====================
-- SEED DATA: Tipos de Ausencia Base
-- =====================

-- Nota: Este seed se ejecuta por tenant cuando se crea la empresa
-- Aqui solo documentamos los tipos base

/*
INSERT INTO hr.leave_types (tenant_id, company_id, name, code, leave_category, allocation_type, requires_approval, is_paid, max_days_per_year) VALUES
-- Vacaciones (Mexico: 12 dias primer ano, incrementa)
(tenant_id, company_id, 'Vacaciones', 'VAC', 'vacation', 'fixed', true, true, 30),
-- Enfermedad
(tenant_id, company_id, 'Incapacidad por Enfermedad', 'SICK', 'sick', 'unlimited', false, true, NULL),
-- Maternidad (Mexico: 84 dias)
(tenant_id, company_id, 'Licencia de Maternidad', 'MAT', 'maternity', 'fixed', true, true, 84),
-- Paternidad (Mexico: 5 dias)
(tenant_id, company_id, 'Licencia de Paternidad', 'PAT', 'paternity', 'fixed', true, true, 5),
-- Luto
(tenant_id, company_id, 'Permiso por Luto', 'BER', 'bereavement', 'fixed', true, true, 5),
-- Personal sin goce
(tenant_id, company_id, 'Permiso Personal (Sin Goce)', 'UNPAID', 'unpaid', 'unlimited', true, false, NULL),
-- Personal con goce
(tenant_id, company_id, 'Permiso Personal (Con Goce)', 'PERS', 'personal', 'fixed', true, true, 3);
*/

-- =====================
-- COMENTARIOS
-- =====================
COMMENT ON SCHEMA hr IS 'Schema para gestion de Recursos Humanos';
COMMENT ON TABLE hr.departments IS 'Departamentos organizacionales con jerarquia';
COMMENT ON TABLE hr.job_positions IS 'Puestos de trabajo';
COMMENT ON TABLE hr.employees IS 'Empleados de la empresa';
COMMENT ON TABLE hr.contracts IS 'Contratos laborales';
COMMENT ON TABLE hr.leave_types IS 'Tipos de ausencia configurables';
COMMENT ON TABLE hr.leave_allocations IS 'Asignacion de dias por empleado y tipo';
COMMENT ON TABLE hr.leaves IS 'Solicitudes de ausencia';
COMMENT ON FUNCTION hr.get_direct_subordinates IS 'Obtiene subordinados directos de un manager';
COMMENT ON FUNCTION hr.get_leave_balance IS 'Obtiene saldo de dias de ausencia';
COMMENT ON FUNCTION hr.get_active_contract IS 'Obtiene contrato activo de un empleado';
COMMENT ON FUNCTION hr.check_leave_overlap IS 'Verifica solapamiento de ausencias';
