-- ============================================================================
-- ASSETS SCHEMA - MMD-013 Asset Management
-- Mecánicas Diesel - ERP Suite
-- ============================================================================
-- Schema for asset/tool management with assignment tracking, audits, and maintenance
-- ============================================================================

-- Create schema
CREATE SCHEMA IF NOT EXISTS assets;

-- Set search path
SET search_path TO assets, public;

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

CREATE TYPE asset_status AS ENUM (
    'available',
    'assigned',
    'in_maintenance',
    'damaged',
    'retired'
);

CREATE TYPE asset_location AS ENUM (
    'warehouse',
    'unit',
    'technician',
    'external'
);

CREATE TYPE criticality_level AS ENUM (
    'low',
    'medium',
    'high',
    'critical'
);

CREATE TYPE assignee_type AS ENUM (
    'employee',
    'unit',
    'location'
);

CREATE TYPE assignment_status AS ENUM (
    'active',
    'returned',
    'overdue',
    'lost',
    'damaged'
);

CREATE TYPE audit_status AS ENUM (
    'in_progress',
    'completed',
    'cancelled'
);

CREATE TYPE audit_item_status AS ENUM (
    'found',
    'missing',
    'damaged',
    'extra'
);

CREATE TYPE item_condition AS ENUM (
    'good',
    'fair',
    'poor'
);

CREATE TYPE maintenance_type AS ENUM (
    'preventive',
    'corrective',
    'calibration'
);

CREATE TYPE maintenance_status AS ENUM (
    'scheduled',
    'in_progress',
    'completed',
    'cancelled'
);

-- ============================================================================
-- TABLE: asset_categories
-- ============================================================================

CREATE TABLE asset_categories (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,
    name VARCHAR(100) NOT NULL,
    description TEXT,
    parent_id UUID REFERENCES asset_categories(id) ON DELETE SET NULL,
    requires_service_types TEXT[], -- Service types that require this category
    sort_order INTEGER DEFAULT 0,
    is_active BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),

    CONSTRAINT uq_asset_categories_name UNIQUE (tenant_id, name)
);

CREATE INDEX idx_asset_categories_tenant ON asset_categories(tenant_id);
CREATE INDEX idx_asset_categories_parent ON asset_categories(parent_id);

-- ============================================================================
-- TABLE: assets
-- ============================================================================

CREATE TABLE assets (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,
    code VARCHAR(50) NOT NULL,
    name VARCHAR(150) NOT NULL,
    description TEXT,
    category_id UUID NOT NULL REFERENCES asset_categories(id),
    serial_number VARCHAR(100),
    qr_code VARCHAR(100),
    barcode VARCHAR(100),
    manufacturer VARCHAR(100),
    model VARCHAR(100),
    purchase_date DATE,
    purchase_cost DECIMAL(12, 2),
    warranty_expiry DATE,
    status asset_status DEFAULT 'available',
    current_location asset_location DEFAULT 'warehouse',
    current_assignee_id UUID,
    current_assignee_type assignee_type,
    criticality criticality_level DEFAULT 'medium',
    requires_calibration BOOLEAN DEFAULT FALSE,
    last_calibration_date DATE,
    next_calibration_date DATE,
    photo_url TEXT,
    metadata JSONB DEFAULT '{}',
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    created_by UUID,

    CONSTRAINT uq_assets_code UNIQUE (tenant_id, code),
    CONSTRAINT uq_assets_qr_code UNIQUE (tenant_id, qr_code),
    CONSTRAINT uq_assets_barcode UNIQUE (tenant_id, barcode)
);

CREATE INDEX idx_assets_tenant ON assets(tenant_id);
CREATE INDEX idx_assets_category ON assets(category_id);
CREATE INDEX idx_assets_status ON assets(status);
CREATE INDEX idx_assets_location ON assets(current_location);
CREATE INDEX idx_assets_assignee ON assets(current_assignee_id);
CREATE INDEX idx_assets_qr ON assets(qr_code) WHERE qr_code IS NOT NULL;
CREATE INDEX idx_assets_barcode ON assets(barcode) WHERE barcode IS NOT NULL;
CREATE INDEX idx_assets_calibration ON assets(next_calibration_date) WHERE requires_calibration = TRUE;

-- ============================================================================
-- TABLE: asset_assignments
-- ============================================================================

CREATE TABLE asset_assignments (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,
    asset_id UUID NOT NULL REFERENCES assets(id),
    assignee_id UUID NOT NULL,
    assignee_type assignee_type NOT NULL,
    assigned_at TIMESTAMPTZ DEFAULT NOW(),
    assigned_by UUID NOT NULL,
    expected_return_at TIMESTAMPTZ,
    actual_return_at TIMESTAMPTZ,
    returned_to UUID,
    status assignment_status DEFAULT 'active',
    assignment_photo_url TEXT,
    return_photo_url TEXT,
    notes TEXT,
    signature_url TEXT,
    incident_id UUID, -- FK to rescue_order if applicable
    metadata JSONB DEFAULT '{}',
    created_at TIMESTAMPTZ DEFAULT NOW(),

    CONSTRAINT chk_return_dates CHECK (actual_return_at IS NULL OR actual_return_at >= assigned_at)
);

CREATE INDEX idx_asset_assignments_tenant ON asset_assignments(tenant_id);
CREATE INDEX idx_asset_assignments_asset ON asset_assignments(asset_id);
CREATE INDEX idx_asset_assignments_assignee ON asset_assignments(assignee_id, assignee_type);
CREATE INDEX idx_asset_assignments_status ON asset_assignments(status);
CREATE INDEX idx_asset_assignments_incident ON asset_assignments(incident_id) WHERE incident_id IS NOT NULL;
CREATE INDEX idx_asset_assignments_active ON asset_assignments(asset_id) WHERE status = 'active';

-- ============================================================================
-- TABLE: asset_audits
-- ============================================================================

CREATE TABLE asset_audits (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,
    audit_date DATE NOT NULL,
    auditor_id UUID NOT NULL,
    location_id UUID,
    unit_id UUID,
    technician_id UUID,
    status audit_status DEFAULT 'in_progress',
    total_assets INTEGER DEFAULT 0,
    found_assets INTEGER DEFAULT 0,
    missing_assets INTEGER DEFAULT 0,
    damaged_assets INTEGER DEFAULT 0,
    notes TEXT,
    started_at TIMESTAMPTZ DEFAULT NOW(),
    completed_at TIMESTAMPTZ,
    metadata JSONB DEFAULT '{}',
    created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_asset_audits_tenant ON asset_audits(tenant_id);
CREATE INDEX idx_asset_audits_date ON asset_audits(audit_date);
CREATE INDEX idx_asset_audits_auditor ON asset_audits(auditor_id);
CREATE INDEX idx_asset_audits_status ON asset_audits(status);
CREATE INDEX idx_asset_audits_unit ON asset_audits(unit_id) WHERE unit_id IS NOT NULL;
CREATE INDEX idx_asset_audits_technician ON asset_audits(technician_id) WHERE technician_id IS NOT NULL;

-- ============================================================================
-- TABLE: asset_audit_items
-- ============================================================================

CREATE TABLE asset_audit_items (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    audit_id UUID NOT NULL REFERENCES asset_audits(id) ON DELETE CASCADE,
    asset_id UUID REFERENCES assets(id),
    status audit_item_status NOT NULL,
    condition item_condition,
    notes TEXT,
    photo_url TEXT,
    scanned_at TIMESTAMPTZ DEFAULT NOW(),
    scanned_by UUID,

    CONSTRAINT uq_audit_items_asset UNIQUE (audit_id, asset_id)
);

CREATE INDEX idx_asset_audit_items_audit ON asset_audit_items(audit_id);
CREATE INDEX idx_asset_audit_items_asset ON asset_audit_items(asset_id);
CREATE INDEX idx_asset_audit_items_status ON asset_audit_items(status);

-- ============================================================================
-- TABLE: asset_maintenance
-- ============================================================================

CREATE TABLE asset_maintenance (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,
    asset_id UUID NOT NULL REFERENCES assets(id),
    maintenance_type maintenance_type NOT NULL,
    scheduled_date DATE,
    performed_date DATE,
    performed_by UUID,
    external_vendor VARCHAR(200),
    cost DECIMAL(12, 2),
    description TEXT NOT NULL,
    result TEXT,
    next_maintenance_date DATE,
    status maintenance_status DEFAULT 'scheduled',
    metadata JSONB DEFAULT '{}',
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    created_by UUID
);

CREATE INDEX idx_asset_maintenance_tenant ON asset_maintenance(tenant_id);
CREATE INDEX idx_asset_maintenance_asset ON asset_maintenance(asset_id);
CREATE INDEX idx_asset_maintenance_type ON asset_maintenance(maintenance_type);
CREATE INDEX idx_asset_maintenance_status ON asset_maintenance(status);
CREATE INDEX idx_asset_maintenance_scheduled ON asset_maintenance(scheduled_date) WHERE status = 'scheduled';

-- ============================================================================
-- FUNCTIONS
-- ============================================================================

-- Function to update asset status when assigned
CREATE OR REPLACE FUNCTION update_asset_on_assignment()
RETURNS TRIGGER AS $$
BEGIN
    IF NEW.status = 'active' THEN
        UPDATE assets
        SET
            status = 'assigned',
            current_location = CASE NEW.assignee_type
                WHEN 'employee' THEN 'technician'
                WHEN 'unit' THEN 'unit'
                ELSE 'external'
            END,
            current_assignee_id = NEW.assignee_id,
            current_assignee_type = NEW.assignee_type,
            updated_at = NOW()
        WHERE id = NEW.asset_id;
    ELSIF NEW.status IN ('returned', 'lost', 'damaged') AND OLD.status = 'active' THEN
        UPDATE assets
        SET
            status = CASE NEW.status
                WHEN 'lost' THEN 'retired'
                WHEN 'damaged' THEN 'damaged'
                ELSE 'available'
            END,
            current_location = 'warehouse',
            current_assignee_id = NULL,
            current_assignee_type = NULL,
            updated_at = NOW()
        WHERE id = NEW.asset_id;
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_asset_assignment_status
    AFTER INSERT OR UPDATE OF status ON asset_assignments
    FOR EACH ROW
    EXECUTE FUNCTION update_asset_on_assignment();

-- Function to update audit counts
CREATE OR REPLACE FUNCTION update_audit_counts()
RETURNS TRIGGER AS $$
BEGIN
    UPDATE asset_audits
    SET
        total_assets = (SELECT COUNT(*) FROM asset_audit_items WHERE audit_id = COALESCE(NEW.audit_id, OLD.audit_id)),
        found_assets = (SELECT COUNT(*) FROM asset_audit_items WHERE audit_id = COALESCE(NEW.audit_id, OLD.audit_id) AND status = 'found'),
        missing_assets = (SELECT COUNT(*) FROM asset_audit_items WHERE audit_id = COALESCE(NEW.audit_id, OLD.audit_id) AND status = 'missing'),
        damaged_assets = (SELECT COUNT(*) FROM asset_audit_items WHERE audit_id = COALESCE(NEW.audit_id, OLD.audit_id) AND status = 'damaged')
    WHERE id = COALESCE(NEW.audit_id, OLD.audit_id);
    RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_audit_items_count
    AFTER INSERT OR UPDATE OR DELETE ON asset_audit_items
    FOR EACH ROW
    EXECUTE FUNCTION update_audit_counts();

-- Function to auto-update timestamps
CREATE OR REPLACE FUNCTION assets_update_timestamp()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

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

CREATE TRIGGER trg_asset_maintenance_updated_at
    BEFORE UPDATE ON asset_maintenance
    FOR EACH ROW
    EXECUTE FUNCTION assets_update_timestamp();

CREATE TRIGGER trg_asset_categories_updated_at
    BEFORE UPDATE ON asset_categories
    FOR EACH ROW
    EXECUTE FUNCTION assets_update_timestamp();

-- ============================================================================
-- VIEWS
-- ============================================================================

-- View: Assets with current assignment info
CREATE OR REPLACE VIEW vw_assets_with_assignment AS
SELECT
    a.*,
    c.name AS category_name,
    aa.id AS active_assignment_id,
    aa.assignee_id,
    aa.assignee_type,
    aa.assigned_at,
    aa.expected_return_at,
    CASE
        WHEN aa.expected_return_at IS NOT NULL AND aa.expected_return_at < NOW()
        THEN TRUE
        ELSE FALSE
    END AS is_overdue
FROM assets a
LEFT JOIN asset_categories c ON a.category_id = c.id
LEFT JOIN asset_assignments aa ON a.id = aa.asset_id AND aa.status = 'active';

-- View: Assets requiring calibration soon
CREATE OR REPLACE VIEW vw_assets_calibration_due AS
SELECT
    a.id,
    a.tenant_id,
    a.code,
    a.name,
    a.next_calibration_date,
    a.current_location,
    a.current_assignee_id,
    EXTRACT(DAY FROM a.next_calibration_date - NOW()) AS days_until_due
FROM assets a
WHERE a.requires_calibration = TRUE
  AND a.status != 'retired'
  AND a.next_calibration_date <= NOW() + INTERVAL '30 days'
ORDER BY a.next_calibration_date;

-- View: Asset assignment history
CREATE OR REPLACE VIEW vw_asset_assignment_history AS
SELECT
    aa.*,
    a.code AS asset_code,
    a.name AS asset_name,
    a.category_id,
    c.name AS category_name
FROM asset_assignments aa
JOIN assets a ON aa.asset_id = a.id
JOIN asset_categories c ON a.category_id = c.id
ORDER BY aa.assigned_at DESC;

-- View: Audit summary
CREATE OR REPLACE VIEW vw_audit_summary AS
SELECT
    au.id,
    au.tenant_id,
    au.audit_date,
    au.auditor_id,
    au.status,
    au.total_assets,
    au.found_assets,
    au.missing_assets,
    au.damaged_assets,
    CASE
        WHEN au.total_assets > 0
        THEN ROUND((au.found_assets::DECIMAL / au.total_assets) * 100, 2)
        ELSE 0
    END AS accuracy_percentage,
    au.started_at,
    au.completed_at,
    EXTRACT(EPOCH FROM (COALESCE(au.completed_at, NOW()) - au.started_at)) / 60 AS duration_minutes
FROM asset_audits au;

-- ============================================================================
-- ROW LEVEL SECURITY
-- ============================================================================

-- Enable RLS on all tables
ALTER TABLE asset_categories ENABLE ROW LEVEL SECURITY;
ALTER TABLE assets ENABLE ROW LEVEL SECURITY;
ALTER TABLE asset_assignments ENABLE ROW LEVEL SECURITY;
ALTER TABLE asset_audits ENABLE ROW LEVEL SECURITY;
ALTER TABLE asset_audit_items ENABLE ROW LEVEL SECURITY;
ALTER TABLE asset_maintenance ENABLE ROW LEVEL SECURITY;

-- Create policies for tenant isolation
CREATE POLICY asset_categories_tenant_isolation ON asset_categories
    USING (tenant_id = current_setting('app.current_tenant')::UUID);

CREATE POLICY assets_tenant_isolation ON assets
    USING (tenant_id = current_setting('app.current_tenant')::UUID);

CREATE POLICY asset_assignments_tenant_isolation ON asset_assignments
    USING (tenant_id = current_setting('app.current_tenant')::UUID);

CREATE POLICY asset_audits_tenant_isolation ON asset_audits
    USING (tenant_id = current_setting('app.current_tenant')::UUID);

CREATE POLICY asset_audit_items_tenant_isolation ON asset_audit_items
    USING (audit_id IN (SELECT id FROM asset_audits WHERE tenant_id = current_setting('app.current_tenant')::UUID));

CREATE POLICY asset_maintenance_tenant_isolation ON asset_maintenance
    USING (tenant_id = current_setting('app.current_tenant')::UUID);

-- ============================================================================
-- SEED DATA (sample categories)
-- ============================================================================

-- Note: In production, seed data should be added via migration scripts
-- These are example categories for reference:
/*
INSERT INTO asset_categories (tenant_id, name, description, sort_order) VALUES
    ('00000000-0000-0000-0000-000000000001', 'Herramientas Manuales', 'Llaves, desarmadores, pinzas', 1),
    ('00000000-0000-0000-0000-000000000001', 'Herramientas Eléctricas', 'Taladros, esmeriles, etc.', 2),
    ('00000000-0000-0000-0000-000000000001', 'Equipos de Diagnóstico', 'Scanners, multímetros', 3),
    ('00000000-0000-0000-0000-000000000001', 'Equipos de Rescate', 'Grúas, gatos hidráulicos', 4),
    ('00000000-0000-0000-0000-000000000001', 'Equipos de Seguridad', 'EPP, señalización', 5),
    ('00000000-0000-0000-0000-000000000001', 'Equipos de Medición', 'Calibradores, manómetros', 6);
*/

-- ============================================================================
-- GRANTS (adjust based on your database roles)
-- ============================================================================

-- Grant usage on schema
-- GRANT USAGE ON SCHEMA assets TO app_user;
-- GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA assets TO app_user;
-- GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA assets TO app_user;

COMMENT ON SCHEMA assets IS 'MMD-013: Asset and tool management module';
COMMENT ON TABLE assets IS 'Master table for all trackable assets and tools';
COMMENT ON TABLE asset_categories IS 'Hierarchical categorization of assets';
COMMENT ON TABLE asset_assignments IS 'Track asset assignments to employees, units, or locations';
COMMENT ON TABLE asset_audits IS 'Physical inventory audits';
COMMENT ON TABLE asset_audit_items IS 'Individual items checked during an audit';
COMMENT ON TABLE asset_maintenance IS 'Maintenance records including calibration';
