-- ============================================
-- SCHEMA BASE DE DATOS - SERVIDOR DE CONTENIDO TES
-- ============================================
-- 
-- PostgreSQL en servidor propio
-- Schema: tes_content
-- 
-- @version 1.0.0
-- @date 2025-01-06
-- ============================================

-- Crear schema
CREATE SCHEMA IF NOT EXISTS tes_content;

-- ============================================
-- EXTENSIONES
-- ============================================

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm"; -- Para búsqueda de texto

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

CREATE TYPE tes_content.content_type AS ENUM (
  'protocol',
  'guide',
  'manual',
  'drug',
  'checklist'
);

CREATE TYPE tes_content.usage_type AS ENUM (
  'operativo',
  'formativo',
  'referencia'
);

CREATE TYPE tes_content.priority AS ENUM (
  'critica',
  'alta',
  'media',
  'baja'
);

CREATE TYPE tes_content.content_status AS ENUM (
  'draft',
  'in_review',
  'approved',
  'published',
  'archived'
);

CREATE TYPE tes_content.media_type AS ENUM (
  'image',
  'video'
);

CREATE TYPE tes_content.clinical_context AS ENUM (
  'RCP',
  'OVACE',
  'ABCDE',
  'TRIAGE',
  'GLASGOW',
  'ICTUS',
  'SHOCK',
  'TRAUMA',
  'OXIGENOTERAPIA',
  'VIA_AEREA',
  'FARMACOLOGIA',
  'OTROS'
);

CREATE TYPE tes_content.source_guideline AS ENUM (
  'ERC',
  'SEMES',
  'AHA',
  'INTERNO',
  'MANUAL_TES_DIGITAL'
);

-- ============================================
-- TABLA: content_items
-- ============================================

CREATE TABLE tes_content.content_items (
  -- Identificación
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  type tes_content.content_type NOT NULL,
  slug TEXT UNIQUE NOT NULL,
  
  -- Metadatos básicos
  title TEXT NOT NULL,
  short_title TEXT,
  description TEXT,
  
  -- Clasificación clínica
  clinical_context tes_content.clinical_context NOT NULL,
  level tes_content.usage_type NOT NULL, -- 'operativo' | 'formativo' | 'referencia'
  priority tes_content.priority NOT NULL DEFAULT 'media',
  
  -- Estado y validación
  status tes_content.content_status NOT NULL DEFAULT 'draft',
  source_guideline tes_content.source_guideline NOT NULL,
  source_year INTEGER,
  source_url TEXT,
  
  -- Validación clínica
  validated_by UUID,
  validated_at TIMESTAMPTZ,
  validator_role TEXT, -- 'tes' | 'medico' | 'formador'
  validation_expires_at TIMESTAMPTZ,
  
  -- Versionado
  version TEXT NOT NULL DEFAULT '1.0.0',
  latest_version TEXT NOT NULL DEFAULT '1.0.0',
  
  -- Contenido específico (JSONB flexible)
  content JSONB NOT NULL,
  
  -- Relaciones
  related_content_ids UUID[] DEFAULT '{}',
  related_protocol_ids UUID[] DEFAULT '{}',
  related_guide_ids UUID[] DEFAULT '{}',
  related_manual_ids UUID[] DEFAULT '{}',
  
  -- Tags y categorización
  tags TEXT[] DEFAULT '{}',
  category TEXT,
  
  -- Auditoría
  created_by UUID NOT NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_by UUID,
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  
  -- Metadatos adicionales
  metadata JSONB DEFAULT '{}',
  
  -- Constraints
  CONSTRAINT valid_version_format CHECK (version ~ '^\d+\.\d+\.\d+$'),
  CONSTRAINT valid_latest_version_format CHECK (latest_version ~ '^\d+\.\d+\.\d+$')
);

-- ============================================
-- TABLA: media_resources
-- ============================================

CREATE TABLE tes_content.media_resources (
  -- Identificación
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  type tes_content.media_type NOT NULL,
  
  -- Archivo (ruta local en servidor)
  path TEXT NOT NULL,                   -- Ruta relativa (ej: "/media/images/rcp/...")
  filename TEXT NOT NULL,               -- Nombre del archivo
  file_url TEXT,                         -- URL pública (si está en CDN o servidor web)
  thumbnail_url TEXT,                    -- URL del thumbnail (vídeos)
  
  -- Metadatos
  title TEXT NOT NULL,
  description TEXT,
  alt_text TEXT NOT NULL,               -- Texto alternativo (accesibilidad)
  caption TEXT,
  
  -- Clasificación
  tags TEXT[] DEFAULT '{}',
  block TEXT,                           -- Bloque temático
  chapter TEXT,                         -- Capítulo relacionado
  priority tes_content.priority NOT NULL DEFAULT 'media',
  usage_type tes_content.usage_type[] DEFAULT '{}', -- ['operativo', 'formativo']
  
  -- Dimensiones (imágenes)
  width INTEGER,
  height INTEGER,
  format TEXT,                          -- 'png' | 'svg' | 'jpg' | 'webp'
  file_size BIGINT,                     -- Tamaño en bytes
  
  -- Duración (vídeos)
  duration_seconds INTEGER,             -- Duración en segundos
  video_format TEXT,                    -- 'mp4' | 'webm'
  
  -- Fuente
  source TEXT,
  attribution TEXT,
  
  -- Estado
  status tes_content.content_status NOT NULL DEFAULT 'draft',
  
  -- Auditoría
  uploaded_by UUID NOT NULL,
  uploaded_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- ============================================
-- TABLA: content_resource_associations
-- ============================================

CREATE TABLE tes_content.content_resource_associations (
  -- Identificación
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  content_item_id UUID NOT NULL REFERENCES tes_content.content_items(id) ON DELETE CASCADE,
  media_resource_id UUID NOT NULL REFERENCES tes_content.media_resources(id) ON DELETE CASCADE,
  
  -- Contexto de asociación
  section TEXT,                         -- Sección específica (ej: "pasos", "checklist", "guia_seccion_3")
  position INTEGER,                     -- Posición en el contenido (orden)
  placement TEXT DEFAULT 'inline',      -- 'inline' | 'before' | 'after' | 'modal'
  caption TEXT,                         -- Caption específico para este contexto
  
  -- Metadatos
  is_critical BOOLEAN NOT NULL DEFAULT false,
  priority tes_content.priority NOT NULL DEFAULT 'media',
  
  -- Auditoría
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  
  -- Constraints
  CONSTRAINT unique_association UNIQUE (content_item_id, media_resource_id, section, position)
);

-- ============================================
-- TABLA: content_versions
-- ============================================

CREATE TABLE tes_content.content_versions (
  -- Identificación
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  content_item_id UUID NOT NULL REFERENCES tes_content.content_items(id) ON DELETE CASCADE,
  version TEXT NOT NULL,
  
  -- Contenido
  content JSONB NOT NULL,
  
  -- Metadatos
  change_summary TEXT NOT NULL,
  is_breaking BOOLEAN DEFAULT false,
  created_by UUID NOT NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  
  -- Estado
  is_active BOOLEAN NOT NULL DEFAULT false,
  
  -- Constraints
  CONSTRAINT valid_version_format CHECK (version ~ '^\d+\.\d+\.\d+$'),
  CONSTRAINT unique_content_version UNIQUE (content_item_id, version)
);

-- ============================================
-- TABLA: audit_logs
-- ============================================

CREATE TABLE tes_content.audit_logs (
  -- Identificación
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  entity_type TEXT NOT NULL,            -- 'content_item' | 'media_resource' | 'association' | 'version'
  entity_id UUID NOT NULL,
  
  -- Acción
  action TEXT NOT NULL,                -- 'create' | 'update' | 'delete' | 'validate' | 'approve' | 'publish' | 'archive' | 'revert'
  user_id UUID NOT NULL,
  user_role TEXT NOT NULL,              -- 'tes' | 'medico' | 'formador' | 'editor' | 'admin'
  
  -- Metadatos
  metadata JSONB DEFAULT '{}',
  
  -- Timestamp
  timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- ============================================
-- TABLA: users (Panel Admin)
-- ============================================

CREATE TABLE tes_content.users (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  email TEXT UNIQUE NOT NULL,
  username TEXT NOT NULL,
  password_hash TEXT NOT NULL,
  role TEXT NOT NULL DEFAULT 'editor', -- 'super_admin' | 'editor_clinico' | 'editor_formativo' | 'revisor' | 'viewer'
  is_active BOOLEAN NOT NULL DEFAULT true,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  last_login TIMESTAMPTZ
);

-- ============================================
-- ÍNDICES
-- ============================================

-- content_items
CREATE INDEX idx_content_items_type ON tes_content.content_items(type);
CREATE INDEX idx_content_items_level ON tes_content.content_items(level);
CREATE INDEX idx_content_items_status ON tes_content.content_items(status);
CREATE INDEX idx_content_items_priority ON tes_content.content_items(priority);
CREATE INDEX idx_content_items_clinical_context ON tes_content.content_items(clinical_context);
CREATE INDEX idx_content_items_slug ON tes_content.content_items(slug);
CREATE INDEX idx_content_items_tags ON tes_content.content_items USING GIN(tags);
CREATE INDEX idx_content_items_created_at ON tes_content.content_items(created_at DESC);
CREATE INDEX idx_content_items_updated_at ON tes_content.content_items(updated_at DESC);
CREATE INDEX idx_content_items_published ON tes_content.content_items(status, updated_at DESC) WHERE status = 'published';

-- Búsqueda de texto completo
CREATE INDEX idx_content_items_search ON tes_content.content_items USING GIN(
  to_tsvector('spanish', 
    COALESCE(title, '') || ' ' || 
    COALESCE(description, '') || ' ' || 
    COALESCE(short_title, '')
  )
);

-- media_resources
CREATE INDEX idx_media_resources_type ON tes_content.media_resources(type);
CREATE INDEX idx_media_resources_status ON tes_content.media_resources(status);
CREATE INDEX idx_media_resources_priority ON tes_content.media_resources(priority);
CREATE INDEX idx_media_resources_usage_type ON tes_content.media_resources USING GIN(usage_type);
CREATE INDEX idx_media_resources_tags ON tes_content.media_resources USING GIN(tags);
CREATE INDEX idx_media_resources_block ON tes_content.media_resources(block);
CREATE INDEX idx_media_resources_uploaded_at ON tes_content.media_resources(uploaded_at DESC);

-- content_resource_associations
CREATE INDEX idx_associations_content_item ON tes_content.content_resource_associations(content_item_id);
CREATE INDEX idx_associations_media_resource ON tes_content.content_resource_associations(media_resource_id);
CREATE INDEX idx_associations_section ON tes_content.content_resource_associations(section);
CREATE INDEX idx_associations_critical ON tes_content.content_resource_associations(is_critical) WHERE is_critical = true;

-- content_versions
CREATE INDEX idx_versions_content_item ON tes_content.content_versions(content_item_id);
CREATE INDEX idx_versions_version ON tes_content.content_versions(version);
CREATE INDEX idx_versions_active ON tes_content.content_versions(is_active) WHERE is_active = true;
CREATE INDEX idx_versions_created_at ON tes_content.content_versions(created_at DESC);

-- audit_logs
CREATE INDEX idx_audit_entity_type_id ON tes_content.audit_logs(entity_type, entity_id);
CREATE INDEX idx_audit_action ON tes_content.audit_logs(action);
CREATE INDEX idx_audit_user_id ON tes_content.audit_logs(user_id);
CREATE INDEX idx_audit_timestamp ON tes_content.audit_logs(timestamp DESC);

-- users
CREATE INDEX idx_users_email ON tes_content.users(email);
CREATE INDEX idx_users_role ON tes_content.users(role);
CREATE INDEX idx_users_is_active ON tes_content.users(is_active);

-- ============================================
-- FUNCIONES Y TRIGGERS
-- ============================================

-- Función para actualizar updated_at automáticamente
CREATE OR REPLACE FUNCTION tes_content.update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = NOW();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Triggers para updated_at
CREATE TRIGGER update_content_items_updated_at
  BEFORE UPDATE ON tes_content.content_items
  FOR EACH ROW
  EXECUTE FUNCTION tes_content.update_updated_at_column();

CREATE TRIGGER update_media_resources_updated_at
  BEFORE UPDATE ON tes_content.media_resources
  FOR EACH ROW
  EXECUTE FUNCTION tes_content.update_updated_at_column();

CREATE TRIGGER update_users_updated_at
  BEFORE UPDATE ON tes_content.users
  FOR EACH ROW
  EXECUTE FUNCTION tes_content.update_updated_at_column();

-- ============================================
-- VISTAS ÚTILES
-- ============================================

-- Vista: Contenido publicado con recursos
CREATE OR REPLACE VIEW tes_content.published_content_with_resources AS
SELECT 
  ci.id,
  ci.type,
  ci.slug,
  ci.title,
  ci.short_title,
  ci.clinical_context,
  ci.level,
  ci.priority,
  ci.status,
  ci.version,
  ci.created_at,
  ci.updated_at,
  COUNT(DISTINCT cra.id) as resource_count,
  COUNT(DISTINCT CASE WHEN cra.is_critical = true THEN cra.id END) as critical_resource_count
FROM tes_content.content_items ci
LEFT JOIN tes_content.content_resource_associations cra ON ci.id = cra.content_item_id
WHERE ci.status = 'published'
GROUP BY ci.id;

-- Vista: Recursos sin asociar
CREATE OR REPLACE VIEW tes_content.unassociated_resources AS
SELECT 
  mr.id,
  mr.type,
  mr.title,
  mr.filename,
  mr.priority,
  mr.uploaded_at
FROM tes_content.media_resources mr
LEFT JOIN tes_content.content_resource_associations cra ON mr.id = cra.media_resource_id
WHERE cra.id IS NULL
  AND mr.status = 'published';

-- Vista: Contenido pendiente de validación
CREATE OR REPLACE VIEW tes_content.content_pending_validation AS
SELECT 
  ci.id,
  ci.type,
  ci.title,
  ci.clinical_context,
  ci.status,
  ci.created_at,
  ci.updated_at,
  EXTRACT(EPOCH FROM (NOW() - ci.updated_at)) / 86400 as days_since_update
FROM tes_content.content_items ci
WHERE ci.status IN ('draft', 'in_review')
ORDER BY ci.updated_at DESC;

-- Vista: Estadísticas de contenido
CREATE OR REPLACE VIEW tes_content.content_stats AS
SELECT 
  type,
  status,
  COUNT(*) as count,
  COUNT(CASE WHEN status = 'published' THEN 1 END) as published_count
FROM tes_content.content_items
GROUP BY type, status;

-- ============================================
-- COMENTARIOS
-- ============================================

COMMENT ON SCHEMA tes_content IS 'Schema dedicado para contenido del sistema TES';
COMMENT ON TABLE tes_content.content_items IS 'Tabla principal de contenido: protocolos, guías, manuales, fármacos, checklists';
COMMENT ON TABLE tes_content.media_resources IS 'Recursos multimedia: imágenes y vídeos almacenados en servidor';
COMMENT ON TABLE tes_content.content_resource_associations IS 'Asociación entre contenido y recursos multimedia';
COMMENT ON TABLE tes_content.content_versions IS 'Versiones históricas de contenido para versionado y rollback';
COMMENT ON TABLE tes_content.audit_logs IS 'Registro de auditoría de todas las acciones del sistema';
COMMENT ON TABLE tes_content.users IS 'Usuarios del panel de administración';

-- ============================================
-- PERMISOS (Ajustar según usuario de BD)
-- ============================================

-- Ejemplo (ajustar usuario):
-- GRANT ALL ON SCHEMA tes_content TO tu_usuario;
-- GRANT ALL ON ALL TABLES IN SCHEMA tes_content TO tu_usuario;
-- GRANT ALL ON ALL SEQUENCES IN SCHEMA tes_content TO tu_usuario;

-- ============================================
-- FIN DEL SCHEMA
-- ============================================

