-- =============================================================
-- ARCHIVO: 60-projects-timesheets.sql
-- DESCRIPCION: Schema de proyectos con soporte para timesheets
-- VERSION: 1.0.0
-- PROYECTO: ERP-Core V2
-- FECHA: 2026-01-20
-- DEPENDE DE: auth schema (tenants, users, companies)
-- =============================================================

-- =====================
-- SCHEMA: projects
-- Schema para modulo de gestion de proyectos
-- =====================
CREATE SCHEMA IF NOT EXISTS projects;

-- =====================
-- EXTENSIONES REQUERIDAS
-- =====================
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- =====================
-- TIPOS ENUMERADOS
-- =====================

-- Estado del proyecto
DO $$ BEGIN
    CREATE TYPE projects.project_status_enum AS ENUM (
        'draft',      -- Borrador
        'active',     -- Activo
        'completed',  -- Completado
        'cancelled',  -- Cancelado
        'on_hold'     -- En espera
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Privacidad del proyecto
DO $$ BEGIN
    CREATE TYPE projects.project_privacy_enum AS ENUM (
        'public',     -- Publico (visible para todos)
        'private',    -- Privado (solo miembros)
        'followers'   -- Solo seguidores
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Estado de la tarea
DO $$ BEGIN
    CREATE TYPE projects.task_status_enum AS ENUM (
        'todo',        -- Por hacer
        'in_progress', -- En progreso
        'review',      -- En revision
        'done',        -- Completada
        'cancelled'    -- Cancelada
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Prioridad de la tarea
DO $$ BEGIN
    CREATE TYPE projects.task_priority_enum AS ENUM (
        'low',    -- Baja
        'normal', -- Normal
        'high',   -- Alta
        'urgent'  -- Urgente
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Estado del timesheet
DO $$ BEGIN
    CREATE TYPE projects.timesheet_status_enum AS ENUM (
        'draft',     -- Borrador
        'submitted', -- Enviado para aprobacion
        'approved',  -- Aprobado
        'rejected'   -- Rechazado
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Estado del milestone
DO $$ BEGIN
    CREATE TYPE projects.milestone_status_enum AS ENUM (
        'pending',   -- Pendiente
        'completed', -- Completado
        'cancelled'  -- Cancelado
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- =====================
-- TABLA: projects
-- Proyectos
-- =====================
CREATE TABLE IF NOT EXISTS projects.projects (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),

    -- Multi-tenant
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
    company_id UUID NOT NULL,

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

    -- Responsables
    manager_id UUID REFERENCES auth.users(id) ON DELETE SET NULL,
    partner_id UUID,  -- Cliente asociado al proyecto

    -- Cuenta analitica (para integracion contable)
    analytic_account_id UUID,

    -- Fechas
    date_start DATE,
    date_end DATE,

    -- Estado y configuracion
    status projects.project_status_enum DEFAULT 'draft',
    privacy projects.project_privacy_enum DEFAULT 'public',
    allow_timesheets BOOLEAN DEFAULT TRUE,
    color VARCHAR(20),

    -- Audit columns
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    created_by UUID REFERENCES auth.users(id),
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_by UUID REFERENCES auth.users(id),
    deleted_at TIMESTAMPTZ,
    deleted_by UUID REFERENCES auth.users(id),

    -- Constraint de unicidad por codigo dentro de company
    UNIQUE(company_id, code)
);

-- Indices para projects
CREATE INDEX IF NOT EXISTS idx_projects_tenant ON projects.projects(tenant_id);
CREATE INDEX IF NOT EXISTS idx_projects_company ON projects.projects(company_id);
CREATE INDEX IF NOT EXISTS idx_projects_manager ON projects.projects(manager_id);
CREATE INDEX IF NOT EXISTS idx_projects_partner ON projects.projects(partner_id);
CREATE INDEX IF NOT EXISTS idx_projects_status ON projects.projects(status);
CREATE INDEX IF NOT EXISTS idx_projects_active ON projects.projects(tenant_id) WHERE deleted_at IS NULL;
CREATE INDEX IF NOT EXISTS idx_projects_code ON projects.projects(code);

-- =====================
-- TABLA: project_stages
-- Etapas/columnas del tablero Kanban
-- =====================
CREATE TABLE IF NOT EXISTS projects.project_stages (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),

    -- Multi-tenant
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

    -- Puede ser global o por proyecto
    project_id UUID REFERENCES projects.projects(id) ON DELETE CASCADE,

    -- Identificacion
    name VARCHAR(100) NOT NULL,
    sequence INT DEFAULT 0,

    -- Configuracion
    fold BOOLEAN DEFAULT FALSE,  -- Columna plegada por defecto
    is_closed BOOLEAN DEFAULT FALSE,  -- Indica etapa de cierre

    -- Audit columns
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

-- Indices para project_stages
CREATE INDEX IF NOT EXISTS idx_project_stages_tenant ON projects.project_stages(tenant_id);
CREATE INDEX IF NOT EXISTS idx_project_stages_project ON projects.project_stages(project_id);
CREATE INDEX IF NOT EXISTS idx_project_stages_sequence ON projects.project_stages(sequence);

-- =====================
-- TABLA: tasks
-- Tareas del proyecto
-- =====================
CREATE TABLE IF NOT EXISTS projects.tasks (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),

    -- Multi-tenant
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

    -- Relaciones
    project_id UUID NOT NULL REFERENCES projects.projects(id) ON DELETE CASCADE,
    stage_id UUID REFERENCES projects.project_stages(id) ON DELETE SET NULL,
    parent_id UUID REFERENCES projects.tasks(id) ON DELETE SET NULL,

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

    -- Asignacion
    assigned_to UUID REFERENCES auth.users(id) ON DELETE SET NULL,

    -- Fechas
    date_deadline DATE,

    -- Estimacion y seguimiento
    estimated_hours DECIMAL(10,2) DEFAULT 0,

    -- Estado y prioridad
    priority projects.task_priority_enum DEFAULT 'normal',
    status projects.task_status_enum DEFAULT 'todo',

    -- Ordenamiento
    sequence INT DEFAULT 0,
    color VARCHAR(20),

    -- Audit columns
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    created_by UUID REFERENCES auth.users(id),
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_by UUID REFERENCES auth.users(id),
    deleted_at TIMESTAMPTZ,
    deleted_by UUID REFERENCES auth.users(id)
);

-- Indices para tasks
CREATE INDEX IF NOT EXISTS idx_tasks_tenant ON projects.tasks(tenant_id);
CREATE INDEX IF NOT EXISTS idx_tasks_project ON projects.tasks(project_id);
CREATE INDEX IF NOT EXISTS idx_tasks_stage ON projects.tasks(stage_id);
CREATE INDEX IF NOT EXISTS idx_tasks_parent ON projects.tasks(parent_id);
CREATE INDEX IF NOT EXISTS idx_tasks_assigned ON projects.tasks(assigned_to);
CREATE INDEX IF NOT EXISTS idx_tasks_status ON projects.tasks(status);
CREATE INDEX IF NOT EXISTS idx_tasks_priority ON projects.tasks(priority);
CREATE INDEX IF NOT EXISTS idx_tasks_deadline ON projects.tasks(date_deadline);
CREATE INDEX IF NOT EXISTS idx_tasks_active ON projects.tasks(tenant_id, project_id) WHERE deleted_at IS NULL;
CREATE INDEX IF NOT EXISTS idx_tasks_sequence ON projects.tasks(project_id, sequence);

-- =====================
-- TABLA: milestones
-- Hitos del proyecto
-- =====================
CREATE TABLE IF NOT EXISTS projects.milestones (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),

    -- Multi-tenant
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

    -- Relacion
    project_id UUID NOT NULL REFERENCES projects.projects(id) ON DELETE CASCADE,

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

    -- Fecha objetivo
    date_deadline DATE,

    -- Estado
    status projects.milestone_status_enum DEFAULT 'pending',

    -- Audit columns
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    created_by UUID REFERENCES auth.users(id),
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_by UUID REFERENCES auth.users(id)
);

-- Indices para milestones
CREATE INDEX IF NOT EXISTS idx_milestones_tenant ON projects.milestones(tenant_id);
CREATE INDEX IF NOT EXISTS idx_milestones_project ON projects.milestones(project_id);
CREATE INDEX IF NOT EXISTS idx_milestones_status ON projects.milestones(status);
CREATE INDEX IF NOT EXISTS idx_milestones_deadline ON projects.milestones(date_deadline);

-- =====================
-- TABLA: timesheets
-- Registro de horas trabajadas (estilo Odoo)
-- =====================
CREATE TABLE IF NOT EXISTS projects.timesheets (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),

    -- Multi-tenant
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
    company_id UUID NOT NULL,

    -- Relaciones
    project_id UUID NOT NULL REFERENCES projects.projects(id) ON DELETE CASCADE,
    task_id UUID REFERENCES projects.tasks(id) ON DELETE SET NULL,
    user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,

    -- Datos del registro
    date DATE NOT NULL,
    hours DECIMAL(5,2) NOT NULL CHECK (hours >= 0 AND hours <= 24),
    description TEXT,

    -- Facturacion
    billable BOOLEAN DEFAULT TRUE,
    invoiced BOOLEAN DEFAULT FALSE,
    invoice_id UUID,  -- FK a factura cuando se facture

    -- Aprobacion
    status projects.timesheet_status_enum DEFAULT 'draft',
    approved_by UUID REFERENCES auth.users(id),
    approved_at TIMESTAMPTZ,

    -- Audit columns
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    created_by UUID REFERENCES auth.users(id),
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_by UUID REFERENCES auth.users(id)
);

-- Indices para timesheets
CREATE INDEX IF NOT EXISTS idx_timesheets_tenant ON projects.timesheets(tenant_id);
CREATE INDEX IF NOT EXISTS idx_timesheets_company ON projects.timesheets(company_id);
CREATE INDEX IF NOT EXISTS idx_timesheets_project ON projects.timesheets(project_id);
CREATE INDEX IF NOT EXISTS idx_timesheets_task ON projects.timesheets(task_id);
CREATE INDEX IF NOT EXISTS idx_timesheets_user ON projects.timesheets(user_id);
CREATE INDEX IF NOT EXISTS idx_timesheets_user_date ON projects.timesheets(user_id, date);
CREATE INDEX IF NOT EXISTS idx_timesheets_date ON projects.timesheets(date);
CREATE INDEX IF NOT EXISTS idx_timesheets_status ON projects.timesheets(status);
CREATE INDEX IF NOT EXISTS idx_timesheets_billable ON projects.timesheets(billable) WHERE billable = TRUE;
CREATE INDEX IF NOT EXISTS idx_timesheets_not_invoiced ON projects.timesheets(project_id, invoiced) WHERE invoiced = FALSE;
CREATE INDEX IF NOT EXISTS idx_timesheets_invoice ON projects.timesheets(invoice_id);

-- =====================
-- TABLA: project_members
-- Miembros del equipo del proyecto
-- =====================
CREATE TABLE IF NOT EXISTS projects.project_members (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),

    -- Multi-tenant
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

    -- Relaciones
    project_id UUID NOT NULL REFERENCES projects.projects(id) ON DELETE CASCADE,
    user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,

    -- Rol en el proyecto
    role VARCHAR(50) DEFAULT 'member',  -- member, contributor, viewer

    -- Audit columns
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,

    -- Un usuario solo puede ser miembro una vez por proyecto
    UNIQUE(project_id, user_id)
);

-- Indices para project_members
CREATE INDEX IF NOT EXISTS idx_project_members_tenant ON projects.project_members(tenant_id);
CREATE INDEX IF NOT EXISTS idx_project_members_project ON projects.project_members(project_id);
CREATE INDEX IF NOT EXISTS idx_project_members_user ON projects.project_members(user_id);

-- =====================
-- COMENTARIOS
-- =====================
COMMENT ON SCHEMA projects IS 'Schema para gestion de proyectos: proyectos, tareas, timesheets, milestones';

COMMENT ON TABLE projects.projects IS 'Proyectos con seguimiento de tareas y timesheets';
COMMENT ON COLUMN projects.projects.allow_timesheets IS 'TRUE si el proyecto permite registro de horas';
COMMENT ON COLUMN projects.projects.analytic_account_id IS 'Cuenta analitica para integracion contable';

COMMENT ON TABLE projects.project_stages IS 'Etapas del tablero Kanban (columnas)';
COMMENT ON COLUMN projects.project_stages.fold IS 'TRUE si la columna debe mostrarse plegada';
COMMENT ON COLUMN projects.project_stages.is_closed IS 'TRUE si representa una etapa de cierre/completado';

COMMENT ON TABLE projects.tasks IS 'Tareas asignables a proyectos';
COMMENT ON COLUMN projects.tasks.estimated_hours IS 'Horas estimadas para completar la tarea';
COMMENT ON COLUMN projects.tasks.parent_id IS 'Referencia a tarea padre para subtareas';

COMMENT ON TABLE projects.milestones IS 'Hitos importantes del proyecto';

COMMENT ON TABLE projects.timesheets IS 'Registro de horas trabajadas estilo Odoo';
COMMENT ON COLUMN projects.timesheets.hours IS 'Horas trabajadas (0-24 por dia)';
COMMENT ON COLUMN projects.timesheets.billable IS 'TRUE si las horas son facturables al cliente';
COMMENT ON COLUMN projects.timesheets.invoiced IS 'TRUE si ya fue incluido en una factura';
COMMENT ON COLUMN projects.timesheets.status IS 'Flujo de aprobacion: draft -> submitted -> approved/rejected';

COMMENT ON TABLE projects.project_members IS 'Miembros del equipo del proyecto';
COMMENT ON COLUMN projects.project_members.role IS 'Rol: member (puede editar), contributor (puede agregar), viewer (solo lectura)';
