/*
-- 1) Crear schema si no existe (no falla si ya existe)
CREATE SCHEMA IF NOT EXISTS demo;
*/
-- 2) Apuntar el search_path al tenant
/*SET search_path TO demo;*/
/* 01_tables_core.sql
   Schema tenant ya seteado: SET search_path TO fernimedi;
   Solo TABLAS, sin FOREIGN KEYS
*/

-- Helper function (se usará en script 03)
CREATE OR REPLACE FUNCTION set_updated_at()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = now();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Empresa
CREATE TABLE IF NOT EXISTS empresa (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  razon_social VARCHAR(200) NOT NULL,
  nombre_comercial VARCHAR(200),
  ruc VARCHAR(11),
  direccion VARCHAR(250),
  telefono VARCHAR(50),
  email VARCHAR(120),
  moneda VARCHAR(3) NOT NULL DEFAULT 'PEN',
  timezone VARCHAR(50) NOT NULL DEFAULT 'America/Lima',
  activo BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS empresa_config (
  empresa_id BIGINT PRIMARY KEY,
  permitir_stock_negativo BOOLEAN NOT NULL DEFAULT TRUE,
  single_session BOOLEAN NOT NULL DEFAULT FALSE,
  requerir_datos_controlados BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- Roles / permisos / usuarios
CREATE TABLE IF NOT EXISTS rol (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  nombre VARCHAR(80) NOT NULL UNIQUE,
  activo BOOLEAN NOT NULL DEFAULT TRUE
);

CREATE TABLE IF NOT EXISTS permiso (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  code VARCHAR(80) NOT NULL UNIQUE,
  descripcion VARCHAR(200)
);

CREATE TABLE IF NOT EXISTS rol_permiso (
  rol_id BIGINT NOT NULL,
  permiso_id BIGINT NOT NULL,
  PRIMARY KEY (rol_id, permiso_id)
);

CREATE TABLE IF NOT EXISTS usuario (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  username VARCHAR(60) NOT NULL UNIQUE,
  password_hash VARCHAR(255) NOT NULL,
  nombres VARCHAR(120) NOT NULL,
  apellidos VARCHAR(120),
  email VARCHAR(120),
  telefono VARCHAR(50),
  rol_id BIGINT NOT NULL,
  activo BOOLEAN NOT NULL DEFAULT TRUE,
  last_login_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS sucursal (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  codigo VARCHAR(20) NOT NULL,
  nombre VARCHAR(120) NOT NULL,
  direccion VARCHAR(250),
  telefono VARCHAR(50),
  responsable_usuario_id BIGINT NULL,
  activo BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (empresa_id, codigo)
);

CREATE TABLE IF NOT EXISTS usuario_sucursal (
  usuario_id BIGINT NOT NULL,
  sucursal_id BIGINT NOT NULL,
  es_principal BOOLEAN NOT NULL DEFAULT FALSE,
  PRIMARY KEY (usuario_id, sucursal_id)
);

CREATE TABLE IF NOT EXISTS user_session (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  usuario_id BIGINT NOT NULL,
  token_hash VARCHAR(255) NOT NULL,
  creado_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  expira_at TIMESTAMPTZ NOT NULL,
  ip VARCHAR(60),
  user_agent TEXT,
  activo BOOLEAN NOT NULL DEFAULT TRUE
);

-- Documentos / series / impresión
CREATE TABLE IF NOT EXISTS tipo_documento (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  codigo VARCHAR(10) NOT NULL UNIQUE,
  nombre VARCHAR(80) NOT NULL
);

CREATE TABLE IF NOT EXISTS serie_documento (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  sucursal_id BIGINT NOT NULL,
  tipo_documento_id BIGINT NOT NULL,
  serie VARCHAR(10) NOT NULL,
  prefijo VARCHAR(5),
  correlativo BIGINT NOT NULL DEFAULT 1,
  activo BOOLEAN NOT NULL DEFAULT TRUE,
  UNIQUE (sucursal_id, tipo_documento_id, serie)
);

CREATE TABLE IF NOT EXISTS printer_profile (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  nombre VARCHAR(80) NOT NULL,
  tipo VARCHAR(30) NOT NULL CHECK (tipo IN ('TICKET_58','TICKET_80','A4','A5')),
  driver VARCHAR(60),
  parametros JSONB NOT NULL DEFAULT '{}'::jsonb,
  activo BOOLEAN NOT NULL DEFAULT TRUE,
  UNIQUE (empresa_id, nombre)
);

CREATE TABLE IF NOT EXISTS sucursal_printer (
  sucursal_id BIGINT NOT NULL,
  tipo_documento_id BIGINT NOT NULL,
  printer_profile_id BIGINT NOT NULL,
  PRIMARY KEY (sucursal_id, tipo_documento_id)
);

CREATE TABLE IF NOT EXISTS medio_pago (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  codigo VARCHAR(20) NOT NULL UNIQUE,
  nombre VARCHAR(60) NOT NULL,
  activo BOOLEAN NOT NULL DEFAULT TRUE
);

-- Terceros
CREATE TABLE IF NOT EXISTS cliente (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  tipo_doc VARCHAR(10),
  nro_doc VARCHAR(20),
  nombres VARCHAR(200) NOT NULL,
  direccion VARCHAR(250),
  telefono VARCHAR(50),
  email VARCHAR(120),
  activo BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (empresa_id, tipo_doc, nro_doc)
);

CREATE TABLE IF NOT EXISTS proveedor (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  ruc VARCHAR(11),
  razon_social VARCHAR(200) NOT NULL,
  direccion VARCHAR(250),
  telefono VARCHAR(50),
  email VARCHAR(120),
  contacto VARCHAR(120),
  activo BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (empresa_id, ruc)
);

-- Productos
CREATE TABLE IF NOT EXISTS categoria_producto (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  nombre VARCHAR(120) NOT NULL,
  activo BOOLEAN NOT NULL DEFAULT TRUE,
  UNIQUE (empresa_id, nombre)
);

CREATE TABLE IF NOT EXISTS unidad_medida (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  codigo VARCHAR(10) NOT NULL UNIQUE,
  nombre VARCHAR(50) NOT NULL
);

CREATE TABLE IF NOT EXISTS principio_activo (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  nombre VARCHAR(200) NOT NULL UNIQUE,
  smiles TEXT,
  formula_molecular VARCHAR(80),
  peso_molecular NUMERIC(12,4)
);

CREATE TABLE IF NOT EXISTS producto (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  categoria_id BIGINT,
  unidad_id BIGINT NOT NULL,
  sku VARCHAR(60),
  codigo_barra VARCHAR(60),
  nombre VARCHAR(250) NOT NULL,
  laboratorio VARCHAR(200),
  forma_farmaceutica VARCHAR(120),
  concentracion VARCHAR(120),
  requiere_receta BOOLEAN NOT NULL DEFAULT FALSE,
  es_controlado BOOLEAN NOT NULL DEFAULT FALSE,
  afecto_igv BOOLEAN NOT NULL DEFAULT TRUE,
  precio_venta NUMERIC(12,2) NOT NULL DEFAULT 0,
  costo_promedio NUMERIC(12,4) NOT NULL DEFAULT 0,
  stock_minimo NUMERIC(12,2) NOT NULL DEFAULT 0,
  activo BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (empresa_id, sku)
);

CREATE TABLE IF NOT EXISTS producto_principio_activo (
  producto_id BIGINT NOT NULL,
  principio_activo_id BIGINT NOT NULL,
  dosis VARCHAR(120),
  PRIMARY KEY (producto_id, principio_activo_id)
);

CREATE TABLE IF NOT EXISTS producto_presentacion (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  producto_id BIGINT NOT NULL,
  nombre VARCHAR(80) NOT NULL,
  unidad_id BIGINT NOT NULL,
  factor_a_base NUMERIC(12,4) NOT NULL CHECK (factor_a_base > 0),
  es_base BOOLEAN NOT NULL DEFAULT FALSE,
  codigo_barra VARCHAR(60),
  UNIQUE (producto_id, nombre)
);

-- Inventario por ubicación/lote
CREATE TABLE IF NOT EXISTS ubicacion (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  sucursal_id BIGINT NOT NULL,
  codigo VARCHAR(30) NOT NULL,
  tipo VARCHAR(20) NOT NULL CHECK (tipo IN ('ALMACEN','VITRINA','DESPENSA')),
  descripcion VARCHAR(120),
  activo BOOLEAN NOT NULL DEFAULT TRUE,
  UNIQUE (sucursal_id, codigo)
);

CREATE TABLE IF NOT EXISTS lote (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  producto_id BIGINT NOT NULL,
  proveedor_id BIGINT NULL,
  codigo_lote VARCHAR(80) NOT NULL,
  vence_el DATE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS stock_lote_ubicacion (
  sucursal_id BIGINT NOT NULL,
  ubicacion_id BIGINT NOT NULL,
  lote_id BIGINT NOT NULL,
  cantidad NUMERIC(12,4) NOT NULL DEFAULT 0,
  PRIMARY KEY (sucursal_id, ubicacion_id, lote_id)
);

CREATE TABLE IF NOT EXISTS mov_inventario (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  sucursal_id BIGINT NOT NULL,
  producto_id BIGINT NOT NULL,
  lote_id BIGINT,
  ubicacion_id BIGINT,
  tipo VARCHAR(20) NOT NULL CHECK (tipo IN ('ENTRADA','SALIDA','AJUSTE')),
  referencia VARCHAR(30) NOT NULL,
  referencia_id BIGINT,
  fecha TIMESTAMPTZ NOT NULL DEFAULT now(),
  cantidad NUMERIC(12,4) NOT NULL CHECK (cantidad > 0),
  costo_unit NUMERIC(12,4) NOT NULL DEFAULT 0,
  nota TEXT
);

-- Listas de precio
CREATE TABLE IF NOT EXISTS lista_precio (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  nombre VARCHAR(80) NOT NULL,
  moneda VARCHAR(3) NOT NULL DEFAULT 'PEN',
  activo BOOLEAN NOT NULL DEFAULT TRUE,
  UNIQUE (empresa_id, nombre)
);

CREATE TABLE IF NOT EXISTS lista_precio_item (
  lista_id BIGINT NOT NULL,
  producto_id BIGINT NOT NULL,
  precio NUMERIC(12,2) NOT NULL CHECK (precio >= 0),
  PRIMARY KEY (lista_id, producto_id)
);

CREATE TABLE IF NOT EXISTS sucursal_lista_precio (
  sucursal_id BIGINT NOT NULL,
  lista_id BIGINT NOT NULL,
  es_default BOOLEAN NOT NULL DEFAULT FALSE,
  PRIMARY KEY (sucursal_id, lista_id)
);

-- Caja
CREATE TABLE IF NOT EXISTS caja (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  sucursal_id BIGINT NOT NULL,
  nombre VARCHAR(80) NOT NULL,
  activo BOOLEAN NOT NULL DEFAULT TRUE,
  UNIQUE (sucursal_id, nombre)
);

CREATE TABLE IF NOT EXISTS arqueo_caja (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  caja_id BIGINT NOT NULL,
  usuario_id BIGINT NOT NULL,
  apertura_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  cierre_at TIMESTAMPTZ,
  monto_apertura NUMERIC(12,2) NOT NULL DEFAULT 0,
  monto_cierre NUMERIC(12,2),
  estado VARCHAR(20) NOT NULL CHECK (estado IN ('ABIERTA','CERRADA'))
);

CREATE TABLE IF NOT EXISTS mov_caja (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  arqueo_id BIGINT NOT NULL,
  tipo VARCHAR(20) NOT NULL CHECK (tipo IN ('INGRESO','EGRESO','COBRO','PAGO')),
  medio_pago_id BIGINT NULL,
  monto NUMERIC(12,2) NOT NULL CHECK (monto > 0),
  referencia VARCHAR(80),
  nota TEXT,
  fecha TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- Cotizaciones
CREATE TABLE IF NOT EXISTS cotizacion (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  sucursal_id BIGINT NOT NULL,
  cliente_id BIGINT,
  usuario_id BIGINT NOT NULL,
  fecha TIMESTAMPTZ NOT NULL DEFAULT now(),
  estado VARCHAR(20) NOT NULL CHECK (estado IN ('PENDIENTE','APROBADA','ANULADA')),
  subtotal NUMERIC(12,2) NOT NULL DEFAULT 0,
  igv NUMERIC(12,2) NOT NULL DEFAULT 0,
  total NUMERIC(12,2) NOT NULL DEFAULT 0,
  nota TEXT
);

CREATE TABLE IF NOT EXISTS cotizacion_detalle (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  cotizacion_id BIGINT NOT NULL,
  producto_id BIGINT NOT NULL,
  presentacion_id BIGINT,
  cantidad NUMERIC(12,4) NOT NULL CHECK (cantidad > 0),
  precio_unit NUMERIC(12,2) NOT NULL CHECK (precio_unit >= 0),
  descuento NUMERIC(12,2) NOT NULL DEFAULT 0,
  total_linea NUMERIC(12,2) NOT NULL DEFAULT 0
);

-- Ventas
CREATE TABLE IF NOT EXISTS venta (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  sucursal_id BIGINT NOT NULL,
  cliente_id BIGINT,
  usuario_id BIGINT NOT NULL,
  arqueo_id BIGINT,
  tipo_documento_id BIGINT NOT NULL,
  serie_documento_id BIGINT NOT NULL,
  numero BIGINT NOT NULL,
  fecha TIMESTAMPTZ NOT NULL DEFAULT now(),
  estado VARCHAR(20) NOT NULL CHECK (estado IN ('EMITIDA','ANULADA')),
  subtotal NUMERIC(12,2) NOT NULL DEFAULT 0,
  igv NUMERIC(12,2) NOT NULL DEFAULT 0,
  total NUMERIC(12,2) NOT NULL DEFAULT 0,
  observacion TEXT,
  UNIQUE (serie_documento_id, numero)
);

CREATE TABLE IF NOT EXISTS venta_detalle (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  venta_id BIGINT NOT NULL,
  producto_id BIGINT NOT NULL,
  presentacion_id BIGINT,
  lote_id BIGINT,
  ubicacion_id BIGINT,
  cantidad NUMERIC(12,4) NOT NULL CHECK (cantidad > 0),
  cantidad_base NUMERIC(12,4),
  precio_unit NUMERIC(12,2) NOT NULL CHECK (precio_unit >= 0),
  descuento NUMERIC(12,2) NOT NULL DEFAULT 0,
  igv NUMERIC(12,2) NOT NULL DEFAULT 0,
  total_linea NUMERIC(12,2) NOT NULL DEFAULT 0
);

CREATE TABLE IF NOT EXISTS venta_pago (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  venta_id BIGINT NOT NULL,
  medio_pago_id BIGINT NOT NULL,
  monto NUMERIC(12,2) NOT NULL CHECK (monto > 0),
  referencia VARCHAR(80)
);

CREATE TABLE IF NOT EXISTS venta_controlado (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  venta_id BIGINT NOT NULL,
  receta_numero VARCHAR(60),
  prescriptor VARCHAR(120),
  colegiatura VARCHAR(40),
  paciente_doc VARCHAR(20),
  observacion TEXT
);

-- Compras
CREATE TABLE IF NOT EXISTS solicitud_compra (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  sucursal_id BIGINT NOT NULL,
  usuario_id BIGINT NOT NULL,
  fecha TIMESTAMPTZ NOT NULL DEFAULT now(),
  estado VARCHAR(20) NOT NULL CHECK (estado IN ('PENDIENTE','APROBADA','RECHAZADA','ATENDIDA')),
  nota TEXT
);

CREATE TABLE IF NOT EXISTS solicitud_compra_detalle (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  solicitud_id BIGINT NOT NULL,
  producto_id BIGINT NOT NULL,
  cantidad NUMERIC(12,4) NOT NULL CHECK (cantidad > 0)
);

CREATE TABLE IF NOT EXISTS compra (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  sucursal_id BIGINT NOT NULL,
  proveedor_id BIGINT NOT NULL,
  usuario_id BIGINT NOT NULL,
  fecha TIMESTAMPTZ NOT NULL DEFAULT now(),
  estado VARCHAR(20) NOT NULL CHECK (estado IN ('REGISTRADA','ANULADA')),
  doc_ref VARCHAR(40),
  subtotal NUMERIC(12,2) NOT NULL DEFAULT 0,
  igv NUMERIC(12,2) NOT NULL DEFAULT 0,
  total NUMERIC(12,2) NOT NULL DEFAULT 0,
  nota TEXT
);

CREATE TABLE IF NOT EXISTS compra_detalle (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  compra_id BIGINT NOT NULL,
  producto_id BIGINT NOT NULL,
  lote_id BIGINT,
  ubicacion_id BIGINT,
  cantidad NUMERIC(12,4) NOT NULL CHECK (cantidad > 0),
  costo_unit NUMERIC(12,4) NOT NULL CHECK (costo_unit >= 0),
  total_linea NUMERIC(12,2) NOT NULL DEFAULT 0
);

-- Puntos
CREATE TABLE IF NOT EXISTS puntos_regla (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  activo BOOLEAN NOT NULL DEFAULT TRUE,
  soles_por_punto NUMERIC(12,2) NOT NULL DEFAULT 1,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS puntos_ledger (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  cliente_id BIGINT NOT NULL,
  fecha TIMESTAMPTZ NOT NULL DEFAULT now(),
  tipo VARCHAR(20) NOT NULL CHECK (tipo IN ('ACUMULA','CANJEA','AJUSTE')),
  puntos INTEGER NOT NULL CHECK (puntos <> 0),
  referencia VARCHAR(30),
  referencia_id BIGINT
);

-- Alertas
CREATE TABLE IF NOT EXISTS alerta (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id BIGINT NOT NULL,
  sucursal_id BIGINT NULL,
  tipo VARCHAR(30) NOT NULL CHECK (tipo IN ('STOCK_NEGATIVO','STOCK_MINIMO','CONTROLADO_SIN_DATOS')),
  severidad VARCHAR(10) NOT NULL CHECK (severidad IN ('INFO','WARN','CRIT')),
  mensaje TEXT NOT NULL,
  payload JSONB NOT NULL DEFAULT '{}'::jsonb,
  creada_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  atendida_at TIMESTAMPTZ
);

CREATE TABLE IF NOT EXISTS alerta_destinatario (
  alerta_id BIGINT NOT NULL,
  usuario_id BIGINT NOT NULL,
  enviado_at TIMESTAMPTZ,
  canal VARCHAR(15) NOT NULL DEFAULT 'IN_APP',
  PRIMARY KEY (alerta_id, usuario_id)
);
