-- ============================================================================
-- 09-assets-schema-ddl.sql
-- Schema: assets
-- ERP Construccion - Modulo Activos, Maquinaria y Mantenimiento (MAE-015)
-- ============================================================================
-- Descripcion: Gestion de activos fijos y maquinaria incluyendo:
--   - Catalogo de activos (maquinaria, equipo, vehiculos)
--   - Asignaciones a obras/proyectos
--   - Planes de mantenimiento preventivo
--   - Ordenes de trabajo de mantenimiento
--   - Historial de mantenimientos
--   - Costeo TCO (Total Cost of Ownership)
--   - Rastreo GPS (IoT)
-- ============================================================================
-- Autor: Claude-Arquitecto-Orquestador
-- Fecha: 2026-01-25
-- Version: 1.0.0
-- ============================================================================

-- Crear schema si no existe
CREATE SCHEMA IF NOT EXISTS assets;

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

-- Tipo de activo
CREATE TYPE assets.asset_type AS ENUM (
    'heavy_machinery',   -- Maquinaria pesada (excavadoras, gruas)
    'light_equipment',   -- Equipo ligero (compactadoras, mezcladoras)
    'vehicle',           -- Vehiculos (camiones, camionetas)
    'tool',              -- Herramientas (taladros, sierras)
    'computer',          -- Equipo de computo
    'furniture',         -- Mobiliario
    'other'              -- Otro
);

-- Estado del activo
CREATE TYPE assets.asset_status AS ENUM (
    'available',      -- Disponible
    'assigned',       -- Asignado a obra
    'in_maintenance', -- En mantenimiento
    'in_transit',     -- En transito entre obras
    'inactive',       -- Inactivo
    'retired',        -- Dado de baja
    'sold'            -- Vendido
);

-- Tipo de propiedad
CREATE TYPE assets.ownership_type AS ENUM (
    'owned',      -- Propio
    'leased',     -- Arrendado
    'rented',     -- Rentado
    'borrowed'    -- Prestamo
);

-- Tipo de mantenimiento
CREATE TYPE assets.maintenance_type AS ENUM (
    'preventive',   -- Preventivo
    'corrective',   -- Correctivo
    'predictive',   -- Predictivo
    'emergency'     -- Emergencia
);

-- Frecuencia de mantenimiento
CREATE TYPE assets.maintenance_frequency AS ENUM (
    'daily',        -- Diario
    'weekly',       -- Semanal
    'biweekly',     -- Quincenal
    'monthly',      -- Mensual
    'quarterly',    -- Trimestral
    'semiannual',   -- Semestral
    'annual',       -- Anual
    'by_hours',     -- Por horas de operacion
    'by_kilometers' -- Por kilometros
);

-- Estado de orden de trabajo
CREATE TYPE assets.work_order_status AS ENUM (
    'draft',        -- Borrador
    'scheduled',    -- Programada
    'in_progress',  -- En progreso
    'on_hold',      -- En espera
    'completed',    -- Completada
    'cancelled'     -- Cancelada
);

-- Prioridad de orden de trabajo
CREATE TYPE assets.work_order_priority AS ENUM (
    'low',       -- Baja
    'medium',    -- Media
    'high',      -- Alta
    'critical'   -- Critica
);

-- Tipo de costo
CREATE TYPE assets.cost_type AS ENUM (
    'maintenance',   -- Mantenimiento
    'repair',        -- Reparacion
    'fuel',          -- Combustible
    'insurance',     -- Seguro
    'tax',           -- Impuestos
    'depreciation',  -- Depreciacion
    'operator',      -- Operador
    'other'          -- Otro
);

-- ============================================================================
-- TABLAS
-- ============================================================================

-- ----------------------------------------------------------------------------
-- 1. Categorias de Activos
-- ----------------------------------------------------------------------------
CREATE TABLE assets.asset_categories (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

    -- Informacion basica
    code VARCHAR(20) NOT NULL,
    name VARCHAR(100) NOT NULL,
    description TEXT,

    -- Jerarquia
    parent_id UUID REFERENCES assets.asset_categories(id),
    level INTEGER NOT NULL DEFAULT 1,

    -- Configuracion de depreciacion
    useful_life_years INTEGER,
    depreciation_method VARCHAR(50), -- straight_line, declining_balance, units_of_production
    salvage_value_percentage DECIMAL(5,2),

    -- Estado
    is_active BOOLEAN NOT NULL DEFAULT TRUE,

    -- Metadatos
    metadata JSONB,

    -- Auditoria
    created_by UUID,
    updated_by UUID,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    deleted_at TIMESTAMPTZ,

    CONSTRAINT uq_asset_categories_tenant_code UNIQUE (tenant_id, code)
);

-- ----------------------------------------------------------------------------
-- 2. Activos (Catalogo Principal)
-- ----------------------------------------------------------------------------
CREATE TABLE assets.assets (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

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

    -- Clasificacion
    category_id UUID REFERENCES assets.asset_categories(id),
    asset_type assets.asset_type NOT NULL,
    status assets.asset_status NOT NULL DEFAULT 'available',
    ownership_type assets.ownership_type NOT NULL DEFAULT 'owned',

    -- Especificaciones tecnicas
    brand VARCHAR(100),
    model VARCHAR(100),
    serial_number VARCHAR(100),
    year_manufactured INTEGER,
    specifications JSONB,

    -- Capacidades
    capacity VARCHAR(100),
    power_rating VARCHAR(50),
    fuel_type VARCHAR(50),
    fuel_capacity DECIMAL(10,2),
    fuel_consumption_rate DECIMAL(10,2), -- litros/hora o km/litro

    -- Metricas de uso
    current_hours DECIMAL(12,2) DEFAULT 0,
    current_kilometers DECIMAL(12,2) DEFAULT 0,
    last_usage_update TIMESTAMPTZ,

    -- Ubicacion actual
    current_project_id UUID,
    current_location_name VARCHAR(255),
    current_latitude DECIMAL(10,8),
    current_longitude DECIMAL(11,8),
    last_location_update TIMESTAMPTZ,

    -- Informacion financiera
    purchase_date DATE,
    purchase_price DECIMAL(18,2),
    purchase_currency VARCHAR(3) DEFAULT 'MXN',
    supplier_id UUID,
    invoice_number VARCHAR(100),

    -- Depreciacion
    useful_life_years INTEGER,
    salvage_value DECIMAL(18,2),
    current_book_value DECIMAL(18,2),
    accumulated_depreciation DECIMAL(18,2) DEFAULT 0,
    depreciation_method VARCHAR(50),
    last_depreciation_date DATE,

    -- Arrendamiento (si aplica)
    lease_start_date DATE,
    lease_end_date DATE,
    lease_monthly_rate DECIMAL(18,2),
    lease_contract_number VARCHAR(100),
    lessor_name VARCHAR(255),

    -- Seguro
    insurance_policy_number VARCHAR(100),
    insurance_company VARCHAR(255),
    insurance_expiry_date DATE,
    insurance_coverage_amount DECIMAL(18,2),

    -- Documentos
    photo_url VARCHAR(500),
    manual_url VARCHAR(500),
    registration_document_url VARCHAR(500),

    -- Proximo mantenimiento
    next_maintenance_date DATE,
    next_maintenance_hours DECIMAL(12,2),
    next_maintenance_kilometers DECIMAL(12,2),

    -- Operador asignado
    assigned_operator_id UUID,

    -- Notas y metadatos
    notes TEXT,
    tags VARCHAR(255)[],
    metadata JSONB,

    -- Auditoria
    created_by UUID,
    updated_by UUID,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    deleted_at TIMESTAMPTZ,

    CONSTRAINT uq_assets_tenant_code UNIQUE (tenant_id, asset_code)
);

-- ----------------------------------------------------------------------------
-- 3. Asignaciones de Activos a Obras
-- ----------------------------------------------------------------------------
CREATE TABLE assets.asset_assignments (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

    -- Activo y proyecto
    asset_id UUID NOT NULL REFERENCES assets.assets(id),
    project_id UUID NOT NULL,
    project_code VARCHAR(50),
    project_name VARCHAR(255),

    -- Periodo de asignacion
    start_date DATE NOT NULL,
    end_date DATE,
    is_current BOOLEAN NOT NULL DEFAULT TRUE,

    -- Ubicacion especifica en obra
    location_in_project VARCHAR(255),
    latitude DECIMAL(10,8),
    longitude DECIMAL(11,8),

    -- Operador asignado
    operator_id UUID,
    operator_name VARCHAR(255),

    -- Responsable
    responsible_id UUID,
    responsible_name VARCHAR(255),

    -- Metricas al inicio/fin
    hours_at_start DECIMAL(12,2),
    hours_at_end DECIMAL(12,2),
    kilometers_at_start DECIMAL(12,2),
    kilometers_at_end DECIMAL(12,2),

    -- Tarifas
    daily_rate DECIMAL(18,2),
    hourly_rate DECIMAL(18,2),

    -- Razon de transferencia
    transfer_reason TEXT,
    transfer_notes TEXT,

    -- Documento de entrega
    delivery_document_url VARCHAR(500),
    return_document_url VARCHAR(500),

    -- Metadatos
    metadata JSONB,

    -- Auditoria
    created_by UUID,
    updated_by UUID,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- ----------------------------------------------------------------------------
-- 4. Planes de Mantenimiento
-- ----------------------------------------------------------------------------
CREATE TABLE assets.maintenance_plans (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

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

    -- Aplica a
    asset_id UUID REFERENCES assets.assets(id), -- Si es especifico de un activo
    category_id UUID REFERENCES assets.asset_categories(id), -- Si aplica a categoria
    asset_type assets.asset_type, -- Si aplica a tipo

    -- Tipo y frecuencia
    maintenance_type assets.maintenance_type NOT NULL DEFAULT 'preventive',
    frequency assets.maintenance_frequency NOT NULL,
    frequency_value INTEGER, -- Cada cuantas unidades (dias, horas, km)

    -- Actividades del plan
    activities JSONB NOT NULL, -- Array de actividades con checklist

    -- Duracion estimada
    estimated_duration_hours DECIMAL(5,2),

    -- Recursos necesarios
    required_parts JSONB, -- Refacciones necesarias
    required_tools JSONB, -- Herramientas necesarias
    required_skills VARCHAR(255)[], -- Habilidades requeridas

    -- Costos estimados
    estimated_labor_cost DECIMAL(18,2),
    estimated_parts_cost DECIMAL(18,2),
    estimated_total_cost DECIMAL(18,2),

    -- Estado
    is_active BOOLEAN NOT NULL DEFAULT TRUE,

    -- Metadatos
    metadata JSONB,

    -- Auditoria
    created_by UUID,
    updated_by UUID,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    deleted_at TIMESTAMPTZ,

    CONSTRAINT uq_maintenance_plans_tenant_code UNIQUE (tenant_id, plan_code)
);

-- ----------------------------------------------------------------------------
-- 5. Programacion de Mantenimientos
-- ----------------------------------------------------------------------------
CREATE TABLE assets.maintenance_schedules (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

    -- Activo y plan
    asset_id UUID NOT NULL REFERENCES assets.assets(id),
    plan_id UUID REFERENCES assets.maintenance_plans(id),

    -- Programacion
    scheduled_date DATE NOT NULL,
    scheduled_hours DECIMAL(12,2), -- Horas del equipo cuando debe hacerse
    scheduled_kilometers DECIMAL(12,2), -- KM cuando debe hacerse

    -- Estado
    status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending, completed, skipped, overdue
    completed_date DATE,

    -- Orden de trabajo generada
    work_order_id UUID,

    -- Alertas
    alert_days_before INTEGER DEFAULT 7,
    alert_sent BOOLEAN DEFAULT FALSE,
    alert_sent_at TIMESTAMPTZ,

    -- Notas
    notes TEXT,

    -- Auditoria
    created_by UUID,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- ----------------------------------------------------------------------------
-- 6. Ordenes de Trabajo de Mantenimiento
-- ----------------------------------------------------------------------------
CREATE TABLE assets.work_orders (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

    -- Identificacion
    work_order_number VARCHAR(50) NOT NULL,

    -- Activo
    asset_id UUID NOT NULL REFERENCES assets.assets(id),
    asset_code VARCHAR(50),
    asset_name VARCHAR(255),

    -- Tipo y estado
    maintenance_type assets.maintenance_type NOT NULL,
    status assets.work_order_status NOT NULL DEFAULT 'draft',
    priority assets.work_order_priority NOT NULL DEFAULT 'medium',

    -- Origen
    schedule_id UUID REFERENCES assets.maintenance_schedules(id),
    plan_id UUID REFERENCES assets.maintenance_plans(id),
    is_scheduled BOOLEAN NOT NULL DEFAULT FALSE,

    -- Descripcion
    title VARCHAR(255) NOT NULL,
    description TEXT,
    problem_reported TEXT,
    diagnosis TEXT,

    -- Ubicacion
    project_id UUID,
    project_name VARCHAR(255),
    location_description VARCHAR(255),

    -- Fechas
    requested_date DATE NOT NULL,
    scheduled_start_date DATE,
    scheduled_end_date DATE,
    actual_start_date DATE,
    actual_end_date DATE,

    -- Metricas del equipo al momento
    hours_at_work_order DECIMAL(12,2),
    kilometers_at_work_order DECIMAL(12,2),

    -- Asignacion
    assigned_to_id UUID,
    assigned_to_name VARCHAR(255),
    team_ids UUID[],

    -- Solicitante
    requested_by_id UUID,
    requested_by_name VARCHAR(255),

    -- Aprobacion
    approved_by_id UUID,
    approved_at TIMESTAMPTZ,

    -- Trabajo realizado
    work_performed TEXT,
    findings TEXT,
    recommendations TEXT,

    -- Checklist de actividades
    activities_checklist JSONB,

    -- Tiempos
    estimated_hours DECIMAL(5,2),
    actual_hours DECIMAL(5,2),

    -- Costos
    labor_cost DECIMAL(18,2) DEFAULT 0,
    parts_cost DECIMAL(18,2) DEFAULT 0,
    external_service_cost DECIMAL(18,2) DEFAULT 0,
    other_costs DECIMAL(18,2) DEFAULT 0,
    total_cost DECIMAL(18,2) DEFAULT 0,

    -- Partes utilizadas (detalle en tabla separada)
    parts_used_count INTEGER DEFAULT 0,

    -- Documentos
    photos_before JSONB, -- URLs de fotos antes
    photos_after JSONB, -- URLs de fotos despues
    documents JSONB, -- URLs de documentos adjuntos

    -- Firma de conformidad
    completed_by_id UUID,
    completed_by_name VARCHAR(255),
    completion_signature_url VARCHAR(500),
    completion_notes TEXT,

    -- Seguimiento
    requires_followup BOOLEAN DEFAULT FALSE,
    followup_notes TEXT,
    followup_work_order_id UUID,

    -- Notas y metadatos
    notes TEXT,
    metadata JSONB,

    -- Auditoria
    created_by UUID,
    updated_by UUID,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    deleted_at TIMESTAMPTZ,

    CONSTRAINT uq_work_orders_tenant_number UNIQUE (tenant_id, work_order_number)
);

-- ----------------------------------------------------------------------------
-- 7. Partes/Refacciones Utilizadas en Ordenes de Trabajo
-- ----------------------------------------------------------------------------
CREATE TABLE assets.work_order_parts (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

    -- Orden de trabajo
    work_order_id UUID NOT NULL REFERENCES assets.work_orders(id) ON DELETE CASCADE,

    -- Parte/Refaccion
    part_id UUID, -- Referencia a inventario si existe
    part_code VARCHAR(50),
    part_name VARCHAR(255) NOT NULL,
    part_description TEXT,

    -- Cantidades
    quantity_required DECIMAL(10,2) NOT NULL,
    quantity_used DECIMAL(10,2),

    -- Costos
    unit_cost DECIMAL(18,2),
    total_cost DECIMAL(18,2),

    -- Origen
    from_inventory BOOLEAN DEFAULT FALSE,
    purchase_order_id UUID, -- Si se compro especificamente

    -- Notas
    notes TEXT,

    -- Auditoria
    created_by UUID,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- ----------------------------------------------------------------------------
-- 8. Historial de Mantenimientos
-- ----------------------------------------------------------------------------
CREATE TABLE assets.maintenance_history (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

    -- Activo
    asset_id UUID NOT NULL REFERENCES assets.assets(id),

    -- Orden de trabajo (si aplica)
    work_order_id UUID REFERENCES assets.work_orders(id),

    -- Fecha y tipo
    maintenance_date DATE NOT NULL,
    maintenance_type assets.maintenance_type NOT NULL,

    -- Descripcion
    description TEXT NOT NULL,
    work_performed TEXT,

    -- Metricas al momento del mantenimiento
    hours_at_maintenance DECIMAL(12,2),
    kilometers_at_maintenance DECIMAL(12,2),

    -- Costos
    labor_cost DECIMAL(18,2) DEFAULT 0,
    parts_cost DECIMAL(18,2) DEFAULT 0,
    total_cost DECIMAL(18,2) DEFAULT 0,

    -- Ejecutor
    performed_by_id UUID,
    performed_by_name VARCHAR(255),
    vendor_name VARCHAR(255), -- Si fue externo

    -- Documentos
    documents JSONB,

    -- Notas
    notes TEXT,

    -- Auditoria
    created_by UUID,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- ----------------------------------------------------------------------------
-- 9. Costos de Activos
-- ----------------------------------------------------------------------------
CREATE TABLE assets.asset_costs (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

    -- Activo
    asset_id UUID NOT NULL REFERENCES assets.assets(id),

    -- Periodo
    period_start DATE NOT NULL,
    period_end DATE NOT NULL,
    fiscal_year INTEGER NOT NULL,
    fiscal_month INTEGER NOT NULL,

    -- Proyecto (si aplica)
    project_id UUID,
    project_code VARCHAR(50),

    -- Tipo de costo
    cost_type assets.cost_type NOT NULL,

    -- Descripcion
    description VARCHAR(255),
    reference_document VARCHAR(100),

    -- Monto
    amount DECIMAL(18,2) NOT NULL,
    currency VARCHAR(3) DEFAULT 'MXN',

    -- Uso asociado
    hours_in_period DECIMAL(12,2),
    kilometers_in_period DECIMAL(12,2),

    -- Calculo de tarifa
    cost_per_hour DECIMAL(18,4),
    cost_per_kilometer DECIMAL(18,4),

    -- Origen
    source_module VARCHAR(50), -- work_order, fuel_log, invoice, etc.
    source_id UUID,

    -- Notas
    notes TEXT,
    metadata JSONB,

    -- Auditoria
    created_by UUID,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- ----------------------------------------------------------------------------
-- 10. Ubicaciones GPS (Historico)
-- ----------------------------------------------------------------------------
CREATE TABLE assets.asset_locations (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

    -- Activo
    asset_id UUID NOT NULL REFERENCES assets.assets(id),

    -- Ubicacion
    latitude DECIMAL(10,8) NOT NULL,
    longitude DECIMAL(11,8) NOT NULL,
    altitude DECIMAL(8,2),
    accuracy DECIMAL(6,2),
    heading DECIMAL(5,2),
    speed DECIMAL(6,2),

    -- Timestamp
    recorded_at TIMESTAMPTZ NOT NULL,

    -- Contexto
    project_id UUID,
    location_name VARCHAR(255),
    address VARCHAR(500),

    -- Telemetria adicional
    engine_status VARCHAR(20), -- on, off, idle
    fuel_level DECIMAL(5,2),
    odometer DECIMAL(12,2),
    engine_hours DECIMAL(12,2),
    battery_voltage DECIMAL(5,2),

    -- Dispositivo
    device_id VARCHAR(100),
    device_type VARCHAR(50),

    -- Metadatos
    raw_data JSONB,

    -- Auditoria
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- ----------------------------------------------------------------------------
-- 11. Registro de Combustible
-- ----------------------------------------------------------------------------
CREATE TABLE assets.fuel_logs (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

    -- Activo
    asset_id UUID NOT NULL REFERENCES assets.assets(id),

    -- Fecha y ubicacion
    log_date DATE NOT NULL,
    log_time TIME,
    project_id UUID,
    location VARCHAR(255),

    -- Combustible
    fuel_type VARCHAR(50) NOT NULL,
    quantity_liters DECIMAL(10,2) NOT NULL,
    unit_price DECIMAL(18,4) NOT NULL,
    total_cost DECIMAL(18,2) NOT NULL,

    -- Metricas al cargar
    odometer_reading DECIMAL(12,2),
    hours_reading DECIMAL(12,2),

    -- Rendimiento calculado
    kilometers_since_last DECIMAL(12,2),
    hours_since_last DECIMAL(12,2),
    liters_per_100km DECIMAL(8,2),
    liters_per_hour DECIMAL(8,2),

    -- Proveedor
    vendor_name VARCHAR(255),
    invoice_number VARCHAR(100),

    -- Operador
    operator_id UUID,
    operator_name VARCHAR(255),

    -- Notas
    notes TEXT,

    -- Auditoria
    created_by UUID,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- ============================================================================
-- INDICES
-- ============================================================================

-- Asset Categories
CREATE INDEX idx_asset_categories_tenant ON assets.asset_categories(tenant_id);
CREATE INDEX idx_asset_categories_parent ON assets.asset_categories(parent_id);

-- Assets
CREATE INDEX idx_assets_tenant ON assets.assets(tenant_id);
CREATE INDEX idx_assets_tenant_type ON assets.assets(tenant_id, asset_type);
CREATE INDEX idx_assets_tenant_status ON assets.assets(tenant_id, status);
CREATE INDEX idx_assets_tenant_category ON assets.assets(tenant_id, category_id);
CREATE INDEX idx_assets_current_project ON assets.assets(tenant_id, current_project_id);
CREATE INDEX idx_assets_serial ON assets.assets(tenant_id, serial_number);

-- Asset Assignments
CREATE INDEX idx_asset_assignments_tenant ON assets.asset_assignments(tenant_id);
CREATE INDEX idx_asset_assignments_asset ON assets.asset_assignments(tenant_id, asset_id);
CREATE INDEX idx_asset_assignments_project ON assets.asset_assignments(tenant_id, project_id);
CREATE INDEX idx_asset_assignments_current ON assets.asset_assignments(tenant_id, is_current) WHERE is_current = TRUE;

-- Maintenance Plans
CREATE INDEX idx_maintenance_plans_tenant ON assets.maintenance_plans(tenant_id);
CREATE INDEX idx_maintenance_plans_asset ON assets.maintenance_plans(tenant_id, asset_id);
CREATE INDEX idx_maintenance_plans_category ON assets.maintenance_plans(tenant_id, category_id);

-- Maintenance Schedules
CREATE INDEX idx_maintenance_schedules_tenant ON assets.maintenance_schedules(tenant_id);
CREATE INDEX idx_maintenance_schedules_asset ON assets.maintenance_schedules(tenant_id, asset_id);
CREATE INDEX idx_maintenance_schedules_date ON assets.maintenance_schedules(tenant_id, scheduled_date);
CREATE INDEX idx_maintenance_schedules_status ON assets.maintenance_schedules(tenant_id, status);

-- Work Orders
CREATE INDEX idx_work_orders_tenant ON assets.work_orders(tenant_id);
CREATE INDEX idx_work_orders_asset ON assets.work_orders(tenant_id, asset_id);
CREATE INDEX idx_work_orders_status ON assets.work_orders(tenant_id, status);
CREATE INDEX idx_work_orders_scheduled_date ON assets.work_orders(tenant_id, scheduled_start_date);
CREATE INDEX idx_work_orders_project ON assets.work_orders(tenant_id, project_id);

-- Work Order Parts
CREATE INDEX idx_work_order_parts_work_order ON assets.work_order_parts(work_order_id);

-- Maintenance History
CREATE INDEX idx_maintenance_history_tenant ON assets.maintenance_history(tenant_id);
CREATE INDEX idx_maintenance_history_asset ON assets.maintenance_history(tenant_id, asset_id);
CREATE INDEX idx_maintenance_history_date ON assets.maintenance_history(tenant_id, maintenance_date);

-- Asset Costs
CREATE INDEX idx_asset_costs_tenant ON assets.asset_costs(tenant_id);
CREATE INDEX idx_asset_costs_asset ON assets.asset_costs(tenant_id, asset_id);
CREATE INDEX idx_asset_costs_period ON assets.asset_costs(tenant_id, period_start, period_end);
CREATE INDEX idx_asset_costs_type ON assets.asset_costs(tenant_id, cost_type);
CREATE INDEX idx_asset_costs_project ON assets.asset_costs(tenant_id, project_id);

-- Asset Locations
CREATE INDEX idx_asset_locations_tenant ON assets.asset_locations(tenant_id);
CREATE INDEX idx_asset_locations_asset ON assets.asset_locations(tenant_id, asset_id);
CREATE INDEX idx_asset_locations_recorded ON assets.asset_locations(tenant_id, recorded_at);
CREATE INDEX idx_asset_locations_geo ON assets.asset_locations USING gist (
    ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)
) WHERE longitude IS NOT NULL AND latitude IS NOT NULL;

-- Fuel Logs
CREATE INDEX idx_fuel_logs_tenant ON assets.fuel_logs(tenant_id);
CREATE INDEX idx_fuel_logs_asset ON assets.fuel_logs(tenant_id, asset_id);
CREATE INDEX idx_fuel_logs_date ON assets.fuel_logs(tenant_id, log_date);

-- ============================================================================
-- ROW LEVEL SECURITY (RLS)
-- ============================================================================

ALTER TABLE assets.asset_categories ENABLE ROW LEVEL SECURITY;
ALTER TABLE assets.assets ENABLE ROW LEVEL SECURITY;
ALTER TABLE assets.asset_assignments ENABLE ROW LEVEL SECURITY;
ALTER TABLE assets.maintenance_plans ENABLE ROW LEVEL SECURITY;
ALTER TABLE assets.maintenance_schedules ENABLE ROW LEVEL SECURITY;
ALTER TABLE assets.work_orders ENABLE ROW LEVEL SECURITY;
ALTER TABLE assets.work_order_parts ENABLE ROW LEVEL SECURITY;
ALTER TABLE assets.maintenance_history ENABLE ROW LEVEL SECURITY;
ALTER TABLE assets.asset_costs ENABLE ROW LEVEL SECURITY;
ALTER TABLE assets.asset_locations ENABLE ROW LEVEL SECURITY;
ALTER TABLE assets.fuel_logs ENABLE ROW LEVEL SECURITY;

-- ============================================================================
-- TRIGGERS DE AUDITORIA
-- ============================================================================

CREATE OR REPLACE FUNCTION assets.set_updated_at()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_asset_categories_updated_at
    BEFORE UPDATE ON assets.asset_categories
    FOR EACH ROW EXECUTE FUNCTION assets.set_updated_at();

CREATE TRIGGER trg_assets_updated_at
    BEFORE UPDATE ON assets.assets
    FOR EACH ROW EXECUTE FUNCTION assets.set_updated_at();

CREATE TRIGGER trg_asset_assignments_updated_at
    BEFORE UPDATE ON assets.asset_assignments
    FOR EACH ROW EXECUTE FUNCTION assets.set_updated_at();

CREATE TRIGGER trg_maintenance_plans_updated_at
    BEFORE UPDATE ON assets.maintenance_plans
    FOR EACH ROW EXECUTE FUNCTION assets.set_updated_at();

CREATE TRIGGER trg_maintenance_schedules_updated_at
    BEFORE UPDATE ON assets.maintenance_schedules
    FOR EACH ROW EXECUTE FUNCTION assets.set_updated_at();

CREATE TRIGGER trg_work_orders_updated_at
    BEFORE UPDATE ON assets.work_orders
    FOR EACH ROW EXECUTE FUNCTION assets.set_updated_at();

CREATE TRIGGER trg_work_order_parts_updated_at
    BEFORE UPDATE ON assets.work_order_parts
    FOR EACH ROW EXECUTE FUNCTION assets.set_updated_at();

CREATE TRIGGER trg_asset_costs_updated_at
    BEFORE UPDATE ON assets.asset_costs
    FOR EACH ROW EXECUTE FUNCTION assets.set_updated_at();

CREATE TRIGGER trg_fuel_logs_updated_at
    BEFORE UPDATE ON assets.fuel_logs
    FOR EACH ROW EXECUTE FUNCTION assets.set_updated_at();

-- ============================================================================
-- FUNCIONES AUXILIARES
-- ============================================================================

-- Funcion para calcular TCO de un activo
CREATE OR REPLACE FUNCTION assets.calculate_asset_tco(
    p_asset_id UUID,
    p_tenant_id UUID,
    p_from_date DATE DEFAULT NULL,
    p_to_date DATE DEFAULT NULL
)
RETURNS TABLE (
    total_cost DECIMAL(18,2),
    maintenance_cost DECIMAL(18,2),
    fuel_cost DECIMAL(18,2),
    depreciation_cost DECIMAL(18,2),
    other_costs DECIMAL(18,2),
    total_hours DECIMAL(12,2),
    total_kilometers DECIMAL(12,2),
    cost_per_hour DECIMAL(18,4),
    cost_per_kilometer DECIMAL(18,4)
) AS $$
DECLARE
    v_from_date DATE;
    v_to_date DATE;
BEGIN
    v_from_date := COALESCE(p_from_date, '1900-01-01'::DATE);
    v_to_date := COALESCE(p_to_date, CURRENT_DATE);

    RETURN QUERY
    SELECT
        COALESCE(SUM(ac.amount), 0) AS total_cost,
        COALESCE(SUM(CASE WHEN ac.cost_type IN ('maintenance', 'repair') THEN ac.amount END), 0) AS maintenance_cost,
        COALESCE(SUM(CASE WHEN ac.cost_type = 'fuel' THEN ac.amount END), 0) AS fuel_cost,
        COALESCE(SUM(CASE WHEN ac.cost_type = 'depreciation' THEN ac.amount END), 0) AS depreciation_cost,
        COALESCE(SUM(CASE WHEN ac.cost_type NOT IN ('maintenance', 'repair', 'fuel', 'depreciation') THEN ac.amount END), 0) AS other_costs,
        COALESCE(SUM(ac.hours_in_period), 0) AS total_hours,
        COALESCE(SUM(ac.kilometers_in_period), 0) AS total_kilometers,
        CASE WHEN SUM(ac.hours_in_period) > 0 THEN SUM(ac.amount) / SUM(ac.hours_in_period) ELSE 0 END AS cost_per_hour,
        CASE WHEN SUM(ac.kilometers_in_period) > 0 THEN SUM(ac.amount) / SUM(ac.kilometers_in_period) ELSE 0 END AS cost_per_kilometer
    FROM assets.asset_costs ac
    WHERE ac.asset_id = p_asset_id
      AND ac.tenant_id = p_tenant_id
      AND ac.period_start >= v_from_date
      AND ac.period_end <= v_to_date;
END;
$$ LANGUAGE plpgsql;

-- Funcion para actualizar proximo mantenimiento de un activo
CREATE OR REPLACE FUNCTION assets.update_next_maintenance()
RETURNS TRIGGER AS $$
BEGIN
    -- Actualizar proximo mantenimiento del activo
    UPDATE assets.assets a
    SET
        next_maintenance_date = (
            SELECT MIN(scheduled_date)
            FROM assets.maintenance_schedules ms
            WHERE ms.asset_id = a.id
              AND ms.status = 'pending'
        ),
        updated_at = NOW()
    WHERE a.id = COALESCE(NEW.asset_id, OLD.asset_id);

    RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_update_next_maintenance
    AFTER INSERT OR UPDATE OR DELETE ON assets.maintenance_schedules
    FOR EACH ROW EXECUTE FUNCTION assets.update_next_maintenance();

-- ============================================================================
-- GAP-002: PRESTAMOS DE HERRAMIENTAS (2026-02-04)
-- ============================================================================

-- Enum para estado de prestamo
CREATE TYPE assets.loan_status AS ENUM (
    'active',       -- Prestamo activo
    'returned',     -- Devuelto
    'overdue',      -- Vencido
    'lost',         -- Extraviado
    'damaged'       -- Danado
);

-- ----------------------------------------------------------------------------
-- 12. Prestamos de Herramientas
-- Registro de prestamos de herramientas entre obras o a empleados
-- ----------------------------------------------------------------------------
CREATE TABLE assets.tool_loans (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

    -- Herramienta prestada
    tool_id UUID NOT NULL REFERENCES assets.assets(id),

    -- Quien recibe el prestamo
    employee_id UUID NOT NULL,
    employee_name VARCHAR(255),

    -- Origen del prestamo
    fraccionamiento_origen_id UUID,
    fraccionamiento_origen_name VARCHAR(255),

    -- Destino del prestamo
    fraccionamiento_destino_id UUID,
    fraccionamiento_destino_name VARCHAR(255),

    -- Fechas
    loan_date DATE NOT NULL,
    expected_return_date DATE,
    actual_return_date DATE,

    -- Estado
    status assets.loan_status NOT NULL DEFAULT 'active',

    -- Condicion
    condition_out TEXT,
    condition_out_photos JSONB,
    condition_in TEXT,
    condition_in_photos JSONB,

    -- Aprobacion
    approved_by_id UUID,
    approved_by_name VARCHAR(255),
    approved_at TIMESTAMPTZ,

    -- Devolucion
    received_by_id UUID,
    received_by_name VARCHAR(255),

    -- Notas
    notes TEXT,
    metadata JSONB,

    -- Auditoria
    created_by UUID,
    updated_by UUID,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Indices para tool_loans
CREATE INDEX idx_tool_loans_tenant ON assets.tool_loans(tenant_id);
CREATE INDEX idx_tool_loans_tool ON assets.tool_loans(tenant_id, tool_id);
CREATE INDEX idx_tool_loans_employee ON assets.tool_loans(tenant_id, employee_id);
CREATE INDEX idx_tool_loans_status ON assets.tool_loans(tenant_id, status);
CREATE INDEX idx_tool_loans_origen ON assets.tool_loans(tenant_id, fraccionamiento_origen_id);
CREATE INDEX idx_tool_loans_destino ON assets.tool_loans(tenant_id, fraccionamiento_destino_id);
CREATE INDEX idx_tool_loans_active ON assets.tool_loans(tenant_id, status) WHERE status = 'active';
CREATE INDEX idx_tool_loans_overdue ON assets.tool_loans(tenant_id, expected_return_date)
    WHERE status = 'active' AND expected_return_date < CURRENT_DATE;

ALTER TABLE assets.tool_loans ENABLE ROW LEVEL SECURITY;

CREATE TRIGGER trg_tool_loans_updated_at
    BEFORE UPDATE ON assets.tool_loans
    FOR EACH ROW EXECUTE FUNCTION assets.set_updated_at();

-- ============================================================================
-- GAP-003: DEPRECIACION DE ACTIVOS (2026-02-04)
-- ============================================================================

-- Enum para metodo de depreciacion
CREATE TYPE assets.depreciation_method AS ENUM (
    'straight_line',      -- Linea recta
    'declining_balance',  -- Saldo decreciente
    'double_declining',   -- Doble saldo decreciente
    'sum_of_years',       -- Suma de digitos de los anos
    'units_of_production' -- Unidades de produccion
);

-- ----------------------------------------------------------------------------
-- 13. Programacion de Depreciacion
-- Configuracion de depreciacion para cada activo
-- ----------------------------------------------------------------------------
CREATE TABLE assets.depreciation_schedule (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

    -- Activo
    asset_id UUID NOT NULL REFERENCES assets.assets(id),

    -- Tipo de activo
    asset_type VARCHAR(20) NOT NULL, -- equipment, machinery, vehicle, tool

    -- Metodo de depreciacion
    method assets.depreciation_method NOT NULL DEFAULT 'straight_line',

    -- Valores
    original_value DECIMAL(18,2) NOT NULL,
    salvage_value DECIMAL(18,2) DEFAULT 0,
    depreciable_amount DECIMAL(18,2) GENERATED ALWAYS AS
        (original_value - COALESCE(salvage_value, 0)) STORED,

    -- Vida util
    useful_life_months INTEGER NOT NULL,
    useful_life_units INTEGER, -- Para units_of_production

    -- Depreciacion mensual calculada (para straight_line)
    monthly_depreciation DECIMAL(12,2) GENERATED ALWAYS AS
        (CASE WHEN useful_life_months > 0
            THEN (original_value - COALESCE(salvage_value, 0)) / useful_life_months
            ELSE 0 END) STORED,

    -- Fechas
    depreciation_start_date DATE NOT NULL,
    depreciation_end_date DATE,

    -- Estado actual
    accumulated_depreciation DECIMAL(18,2) DEFAULT 0,
    current_book_value DECIMAL(18,2),
    last_entry_date DATE,

    -- Estado
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    is_fully_depreciated BOOLEAN NOT NULL DEFAULT FALSE,

    -- Notas
    notes TEXT,
    metadata JSONB,

    -- Auditoria
    created_by UUID,
    updated_by UUID,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    CONSTRAINT uq_depreciation_schedule_asset UNIQUE (tenant_id, asset_id)
);

-- ----------------------------------------------------------------------------
-- 14. Entradas de Depreciacion
-- Registro mensual de depreciacion aplicada
-- ----------------------------------------------------------------------------
CREATE TABLE assets.depreciation_entries (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

    -- Programacion
    schedule_id UUID NOT NULL REFERENCES assets.depreciation_schedule(id) ON DELETE CASCADE,

    -- Periodo
    period_date DATE NOT NULL, -- Primer dia del mes
    fiscal_year INTEGER NOT NULL,
    fiscal_month INTEGER NOT NULL,

    -- Valores
    depreciation_amount DECIMAL(12,2) NOT NULL,
    accumulated_depreciation DECIMAL(18,2) NOT NULL,
    book_value DECIMAL(18,2) NOT NULL,

    -- Para units_of_production
    units_used INTEGER,

    -- Contabilidad
    journal_entry_id UUID,
    is_posted BOOLEAN DEFAULT FALSE,
    posted_at TIMESTAMPTZ,
    posted_by UUID,

    -- Estado
    status VARCHAR(20) NOT NULL DEFAULT 'draft', -- draft, posted, reversed

    -- Notas
    notes TEXT,

    -- Auditoria
    created_by UUID,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    CONSTRAINT uq_depreciation_entries_period UNIQUE (schedule_id, period_date)
);

-- Indices para depreciation_schedule
CREATE INDEX idx_depreciation_schedule_tenant ON assets.depreciation_schedule(tenant_id);
CREATE INDEX idx_depreciation_schedule_asset ON assets.depreciation_schedule(tenant_id, asset_id);
CREATE INDEX idx_depreciation_schedule_active ON assets.depreciation_schedule(tenant_id, is_active) WHERE is_active = TRUE;
CREATE INDEX idx_depreciation_schedule_not_depreciated ON assets.depreciation_schedule(tenant_id, is_fully_depreciated)
    WHERE is_fully_depreciated = FALSE;

-- Indices para depreciation_entries
CREATE INDEX idx_depreciation_entries_tenant ON assets.depreciation_entries(tenant_id);
CREATE INDEX idx_depreciation_entries_schedule ON assets.depreciation_entries(schedule_id);
CREATE INDEX idx_depreciation_entries_period ON assets.depreciation_entries(tenant_id, period_date);
CREATE INDEX idx_depreciation_entries_fiscal ON assets.depreciation_entries(tenant_id, fiscal_year, fiscal_month);
CREATE INDEX idx_depreciation_entries_pending ON assets.depreciation_entries(tenant_id, status) WHERE status = 'draft';

ALTER TABLE assets.depreciation_schedule ENABLE ROW LEVEL SECURITY;
ALTER TABLE assets.depreciation_entries ENABLE ROW LEVEL SECURITY;

CREATE TRIGGER trg_depreciation_schedule_updated_at
    BEFORE UPDATE ON assets.depreciation_schedule
    FOR EACH ROW EXECUTE FUNCTION assets.set_updated_at();

CREATE TRIGGER trg_depreciation_entries_updated_at
    BEFORE UPDATE ON assets.depreciation_entries
    FOR EACH ROW EXECUTE FUNCTION assets.set_updated_at();

-- ============================================================================
-- FUNCION: Calcular depreciacion mensual
-- ============================================================================
CREATE OR REPLACE FUNCTION assets.calculate_monthly_depreciation(
    p_schedule_id UUID,
    p_period_date DATE
)
RETURNS DECIMAL(12,2) AS $$
DECLARE
    v_schedule RECORD;
    v_months_elapsed INTEGER;
    v_depreciation DECIMAL(12,2);
BEGIN
    SELECT * INTO v_schedule
    FROM assets.depreciation_schedule
    WHERE id = p_schedule_id AND is_active = TRUE;

    IF NOT FOUND THEN
        RETURN 0;
    END IF;

    -- Calcular meses transcurridos
    v_months_elapsed := (
        EXTRACT(YEAR FROM p_period_date) * 12 + EXTRACT(MONTH FROM p_period_date)
    ) - (
        EXTRACT(YEAR FROM v_schedule.depreciation_start_date) * 12 + EXTRACT(MONTH FROM v_schedule.depreciation_start_date)
    );

    -- Si ya esta completamente depreciado
    IF v_schedule.accumulated_depreciation >= v_schedule.depreciable_amount THEN
        RETURN 0;
    END IF;

    -- Calcular segun metodo
    CASE v_schedule.method
        WHEN 'straight_line' THEN
            v_depreciation := v_schedule.monthly_depreciation;
        WHEN 'declining_balance' THEN
            v_depreciation := (v_schedule.original_value - v_schedule.accumulated_depreciation) *
                (1.0 / v_schedule.useful_life_months) * 2;
        ELSE
            v_depreciation := v_schedule.monthly_depreciation;
    END CASE;

    -- No depreciar mas del valor depreciable restante
    IF (v_schedule.accumulated_depreciation + v_depreciation) > v_schedule.depreciable_amount THEN
        v_depreciation := v_schedule.depreciable_amount - v_schedule.accumulated_depreciation;
    END IF;

    RETURN COALESCE(v_depreciation, 0);
END;
$$ LANGUAGE plpgsql;

-- ============================================================================
-- COMENTARIOS DE DOCUMENTACION
-- ============================================================================

COMMENT ON SCHEMA assets IS 'Modulo de Activos, Maquinaria y Mantenimiento (MAE-015) - ERP Construccion';

COMMENT ON TABLE assets.asset_categories IS 'Categorias de activos para clasificacion';
COMMENT ON TABLE assets.assets IS 'Catalogo principal de activos (maquinaria, equipo, vehiculos)';
COMMENT ON TABLE assets.asset_assignments IS 'Asignaciones de activos a proyectos/obras';
COMMENT ON TABLE assets.maintenance_plans IS 'Planes de mantenimiento preventivo';
COMMENT ON TABLE assets.maintenance_schedules IS 'Programacion de mantenimientos por activo';
COMMENT ON TABLE assets.work_orders IS 'Ordenes de trabajo de mantenimiento';
COMMENT ON TABLE assets.work_order_parts IS 'Partes/refacciones utilizadas en ordenes de trabajo';
COMMENT ON TABLE assets.maintenance_history IS 'Historial de mantenimientos realizados';
COMMENT ON TABLE assets.asset_costs IS 'Costos de operacion y mantenimiento de activos';
COMMENT ON TABLE assets.asset_locations IS 'Historial de ubicaciones GPS de activos';
COMMENT ON TABLE assets.fuel_logs IS 'Registro de cargas de combustible';
COMMENT ON TABLE assets.tool_loans IS 'Prestamos de herramientas entre obras/empleados (GAP-002)';
COMMENT ON TABLE assets.depreciation_schedule IS 'Configuracion de depreciacion por activo (GAP-003)';
COMMENT ON TABLE assets.depreciation_entries IS 'Entradas mensuales de depreciacion (GAP-003)';

-- ============================================================================
-- FIN DEL SCRIPT
-- ============================================================================
