#!/usr/bin/env python3
"""
Idempotent schema for Fibromuebles-Apps PocketBase (:8102).

Collections (Fase 1 — auth only):
  - users      (auth collection, phone-based)
  - otp_codes  (ephemeral, 5-min codes)

Run again later to add: clientes, pedidos, movimientos (Fases 2-5).

Usage:
  python3 create_collections.py
"""

import json
import os
import sys
import urllib.parse
import urllib.error
import urllib.request

PB_URL = os.environ.get("PB_URL", "http://localhost:8102")
ADMIN_EMAIL = os.environ.get("PB_ADMIN_EMAIL")
ADMIN_PASSWORD = os.environ.get("PB_ADMIN_PASSWORD")


def req(method, path, token=None, body=None):
    headers = {"Content-Type": "application/json"}
    if token:
        headers["Authorization"] = token
    data = json.dumps(body).encode() if body is not None else None
    r = urllib.request.Request(f"{PB_URL}{path}", data=data, method=method, headers=headers)
    try:
        with urllib.request.urlopen(r) as resp:
            return resp.status, json.loads(resp.read().decode() or "{}")
    except urllib.error.HTTPError as e:
        return e.code, json.loads(e.read().decode() or "{}")


def auth_admin():
    if not ADMIN_EMAIL or not ADMIN_PASSWORD:
        print("FATAL: set PB_ADMIN_EMAIL and PB_ADMIN_PASSWORD", file=sys.stderr)
        sys.exit(1)
    code, data = req("POST", "/api/collections/_superusers/auth-with-password",
                     body={"identity": ADMIN_EMAIL, "password": ADMIN_PASSWORD})
    if code != 200:
        print(f"FATAL: admin auth failed: {code} {data}", file=sys.stderr)
        sys.exit(1)
    return data["token"]


def find_collection(token, name):
    code, data = req("GET", f"/api/collections/{name}", token=token)
    return data if code == 200 else None


def upsert_collection(token, schema):
    name = schema["name"]
    existing = find_collection(token, name)
    if existing:
        # Update fields if schema differs (idempotent)
        body = dict(schema)
        body["id"] = existing["id"]
        code, data = req("PATCH", f"/api/collections/{existing['id']}", token=token, body=body)
        if code >= 300:
            print(f"  [warn] {name} update failed: {code} {data}")
        else:
            print(f"  [ok]   {name} updated")
        return existing["id"]
    code, data = req("POST", "/api/collections", token=token, body=schema)
    if code >= 300:
        print(f"  [err]  {name} create failed: {code} {data}", file=sys.stderr)
        sys.exit(1)
    print(f"  [new]  {name} created")
    return data["id"]


def find_record(token, collection, filter_expr):
    qs = urllib.parse.urlencode({"filter": filter_expr})
    code, data = req("GET", f"/api/collections/{collection}/records?{qs}", token=token)
    if code != 200:
        return None
    items = data.get("items", [])
    return items[0] if items else None


def upsert_record_by_name(token, collection, name, payload):
    existing = find_record(token, collection, f'nombre = "{name}"')
    if existing:
        code, data = req(
            "PATCH",
            f"/api/collections/{collection}/records/{existing['id']}",
            token=token,
            body=payload,
        )
        if code >= 300:
            print(f"  [warn] {collection}/{name} seed update failed: {code} {data}")
        return
    code, data = req("POST", f"/api/collections/{collection}/records", token=token, body=payload)
    if code >= 300:
        print(f"  [warn] {collection}/{name} seed create failed: {code} {data}")


USERS_SCHEMA = {
    "name": "users",
    "type": "auth",
    "fields": [
        {"name": "phone",        "type": "text",   "required": True, "presentable": True,
         "max": 16, "min": 12, "pattern": "^549[0-9]{8,12}$"},
        {"name": "name",         "type": "text",   "required": False, "max": 80, "presentable": True},
        {"name": "role",         "type": "select", "required": True,
         "values": ["admin", "empleado"], "maxSelect": 1},
        {"name": "active",       "type": "bool",   "required": False},
    ],
    # Auth options
    "passwordAuth":  {"enabled": True, "identityFields": ["email", "phone"]},
    "otp":           {"enabled": False},
    "mfa":           {"enabled": False},
    "manageRule":    None,
    # API rules: only admins read full list; users read self; nobody self-registers
    "listRule":   "@request.auth.role = 'admin'",
    "viewRule":   "@request.auth.id = id || @request.auth.role = 'admin'",
    "createRule": None,
    "updateRule": "@request.auth.role = 'admin'",
    "deleteRule": "@request.auth.role = 'admin'",
    "indexes": [
        "CREATE UNIQUE INDEX idx_users_phone ON users (phone)",
    ],
}


OTP_CODES_SCHEMA = {
    "name": "otp_codes",
    "type": "base",
    "fields": [
        {"name": "phone",    "type": "text",   "required": True, "max": 16},
        {"name": "code",     "type": "text",   "required": True, "max": 6},
        {"name": "expires",  "type": "date",   "required": True},
        {"name": "attempts", "type": "number", "required": False, "onlyInt": True},
        {"name": "consumed", "type": "bool",   "required": False},
    ],
    "listRule":   None,
    "viewRule":   None,
    "createRule": None,
    "updateRule": None,
    "deleteRule": None,
    "indexes": [
        "CREATE INDEX idx_otp_phone ON otp_codes (phone)",
    ],
}

USER_PERMISSION_MODULES = [
    "inicio", "calculadora", "crm", "presupuestos", "pedidos", "pipeline",
    "cortes", "calendario", "caja", "chatwoot", "clientes", "reportes",
    "configuracion", "proveedores", "catalogo", "tareas",
]


def build_user_permissions_schema(users_id):
    return {
        "name": "user_permissions",
        "type": "base",
        "fields": [
            {"name": "user",       "type": "relation", "required": True,
             "collectionId": users_id, "maxSelect": 1, "cascadeDelete": True, "presentable": True},
            {"name": "module",     "type": "select", "required": True,
             "values": USER_PERMISSION_MODULES, "maxSelect": 1},
            {"name": "can_view",   "type": "bool", "required": False},
            {"name": "can_create", "type": "bool", "required": False},
            {"name": "can_edit",   "type": "bool", "required": False},
            {"name": "can_delete", "type": "bool", "required": False},
        ],
        "listRule":   "@request.auth.id = user || @request.auth.role = 'admin'",
        "viewRule":   "@request.auth.id = user || @request.auth.role = 'admin'",
        "createRule": "@request.auth.role = 'admin'",
        "updateRule": "@request.auth.role = 'admin'",
        "deleteRule": "@request.auth.role = 'admin'",
        "indexes": [
            "CREATE INDEX        idx_user_permissions_user   ON user_permissions (user)",
            "CREATE INDEX        idx_user_permissions_module ON user_permissions (module)",
            "CREATE UNIQUE INDEX idx_user_permissions_unique ON user_permissions (user, module)",
        ],
    }


CLIENTES_SCHEMA = {
    "name": "clientes",
    "type": "base",
    "fields": [
        {"name": "nombre",    "type": "text", "required": True, "max": 120, "presentable": True},
        {"name": "celular",   "type": "text", "required": False, "max": 24,  "presentable": True},
        {"name": "direccion", "type": "text", "required": False, "max": 240},
        {"name": "notas",     "type": "editor", "required": False},
        {"name": "tipo_cliente", "type": "select", "required": False,
         "values": ["persona", "empresa"], "maxSelect": 1},
        {"name": "documento_tipo", "type": "select", "required": False,
         "values": ["dni", "cuil", "cuit"], "maxSelect": 1},
        {"name": "documento_numero", "type": "text", "required": False, "max": 20},
        {"name": "razon_social", "type": "text", "required": False, "max": 160},
        {"name": "contacto_nombre", "type": "text", "required": False, "max": 120},
        {"name": "contacto_celular", "type": "text", "required": False, "max": 24},
    ],
    # Both admin and empleado can read/create/update clientes
    "listRule":   "@request.auth.id != ''",
    "viewRule":   "@request.auth.id != ''",
    "createRule": "@request.auth.id != ''",
    "updateRule": "@request.auth.id != ''",
    "deleteRule": "@request.auth.role = 'admin'",
    "indexes": [
        "CREATE INDEX idx_clientes_celular ON clientes (celular)",
        "CREATE INDEX idx_clientes_nombre  ON clientes (nombre)",
        "CREATE INDEX idx_clientes_documento ON clientes (documento_numero)",
    ],
}


PRESUPUESTO_COUNTERS_SCHEMA = {
    "name": "presupuesto_counters",
    "type": "base",
    "fields": [
        {"name": "anio",          "type": "number", "required": True, "onlyInt": True, "presentable": True},
        {"name": "last_sequence", "type": "number", "required": True, "onlyInt": True},
    ],
    "listRule":   "@request.auth.role = 'admin'",
    "viewRule":   "@request.auth.role = 'admin'",
    "createRule": "@request.auth.role = 'admin'",
    "updateRule": "@request.auth.role = 'admin'",
    "deleteRule": "@request.auth.role = 'admin'",
    "indexes": [
        "CREATE UNIQUE INDEX idx_presupuesto_counters_anio ON presupuesto_counters (anio)",
    ],
}


def build_presupuestos_schema(clientes_id, users_id):
    return {
        "name": "presupuestos",
        "type": "base",
        "fields": [
            {"name": "codigo",      "type": "text",   "required": False, "max": 16, "presentable": True},
            {"name": "anio",        "type": "number", "required": False, "onlyInt": True},
            {"name": "mes",         "type": "number", "required": False, "onlyInt": True},
            {"name": "secuencia",   "type": "number", "required": False, "onlyInt": True},
            {"name": "cliente",     "type": "relation", "required": True,
             "collectionId": clientes_id, "maxSelect": 1, "cascadeDelete": False, "presentable": True},
            {"name": "fecha",       "type": "date",   "required": False},
            {"name": "estado",      "type": "select", "required": True,
             "values": ["borrador", "enviado", "aprobado", "rechazado", "sin_respuesta", "cancelado"], "maxSelect": 1},
            {"name": "cierre_motivo", "type": "select", "required": False,
             "values": ["competencia", "decision_indefinida", "precio_presupuesto", "sin_respuesta", "otro"], "maxSelect": 1},
            {"name": "cierre_nota", "type": "editor", "required": False},
            {"name": "descripcion", "type": "editor", "required": False},
            {"name": "notas",       "type": "editor", "required": False},
            {"name": "total",       "type": "number", "required": False},
            {"name": "pagado",      "type": "number", "required": False},
            {"name": "saldo",       "type": "number", "required": False},
            # Text id to avoid a circular schema dependency; hooks keep it valid.
            {"name": "pedido",      "type": "text",   "required": False, "max": 32},
            {"name": "created_by",  "type": "relation", "required": False,
             "collectionId": users_id, "maxSelect": 1, "cascadeDelete": False},
        ],
        "listRule":   "@request.auth.id != ''",
        "viewRule":   "@request.auth.id != ''",
        "createRule": "@request.auth.id != ''",
        "updateRule": "@request.auth.id != ''",
        "deleteRule": "@request.auth.role = 'admin'",
        "indexes": [
            "CREATE UNIQUE INDEX idx_presupuestos_codigo ON presupuestos (codigo)",
            "CREATE INDEX idx_presupuestos_cliente       ON presupuestos (cliente)",
            "CREATE INDEX idx_presupuestos_estado        ON presupuestos (estado)",
            "CREATE INDEX idx_presupuestos_cierre_motivo ON presupuestos (cierre_motivo)",
            "CREATE INDEX idx_presupuestos_fecha         ON presupuestos (fecha)",
            "CREATE INDEX idx_presupuestos_pedido        ON presupuestos (pedido)",
            "CREATE INDEX idx_presupuestos_anio_seq      ON presupuestos (anio, secuencia)",
        ],
    }


def build_presupuesto_items_schema(presupuestos_id):
    return {
        "name": "presupuesto_items",
        "type": "base",
        "fields": [
            {"name": "presupuesto",     "type": "relation", "required": True,
             "collectionId": presupuestos_id, "maxSelect": 1, "cascadeDelete": True, "presentable": True},
            {"name": "codigo",          "type": "text",   "required": False, "max": 100},
            {"name": "descripcion",     "type": "text",   "required": True, "max": 500, "presentable": True},
            {"name": "cantidad",        "type": "number", "required": True},
            {"name": "precio_unitario", "type": "number", "required": True},
            {"name": "subtotal",        "type": "number", "required": False},
            {"name": "sort_order",      "type": "number", "required": False, "onlyInt": True},
        ],
        "listRule":   "@request.auth.id != ''",
        "viewRule":   "@request.auth.id != ''",
        "createRule": "@request.auth.id != ''",
        "updateRule": "@request.auth.id != ''",
        "deleteRule": "@request.auth.role = 'admin'",
        "indexes": [
            "CREATE INDEX idx_presupuesto_items_presupuesto ON presupuesto_items (presupuesto)",
            "CREATE INDEX idx_presupuesto_items_sort_order  ON presupuesto_items (sort_order)",
        ],
    }


def build_crm_oportunidades_schema(clientes_id, presupuestos_id, users_id):
    return {
        "name": "crm_oportunidades",
        "type": "base",
        "fields": [
            {"name": "titulo",              "type": "text", "required": True, "max": 160, "presentable": True},
            {"name": "cliente",             "type": "relation", "required": True,
             "collectionId": clientes_id, "maxSelect": 1, "cascadeDelete": False, "presentable": True},
            {"name": "origen",              "type": "select", "required": True,
             "values": ["whatsapp", "instagram", "web", "referido", "local", "otro"], "maxSelect": 1},
            {"name": "estado",              "type": "select", "required": True,
             "values": ["nuevo", "contactado", "presupuestar", "presupuestado", "propuesta_enviada", "recalcular_presupuesto", "consulta_analisis", "ultima_oportunidad", "ganado", "perdido", "sin_respuesta"], "maxSelect": 1},
            {"name": "prioridad",           "type": "select", "required": True,
             "values": ["baja", "media", "alta"], "maxSelect": 1},
            {"name": "valor_estimado",      "type": "number", "required": False},
            {"name": "proximo_contacto",    "type": "date", "required": False},
            {"name": "fecha_cambio_estado", "type": "date", "required": False},
            {"name": "nota",                "type": "editor", "required": False},
            {"name": "presupuesto",         "type": "relation", "required": False,
             "collectionId": presupuestos_id, "maxSelect": 1, "cascadeDelete": False},
            {"name": "created_by",          "type": "relation", "required": False,
             "collectionId": users_id, "maxSelect": 1, "cascadeDelete": False},
        ],
        "listRule":   "@request.auth.id != ''",
        "viewRule":   "@request.auth.id != ''",
        "createRule": "@request.auth.id != ''",
        "updateRule": "@request.auth.id != ''",
        "deleteRule": "@request.auth.role = 'admin'",
        "indexes": [
            "CREATE INDEX idx_crm_cliente             ON crm_oportunidades (cliente)",
            "CREATE INDEX idx_crm_estado              ON crm_oportunidades (estado)",
            "CREATE INDEX idx_crm_origen              ON crm_oportunidades (origen)",
            "CREATE INDEX idx_crm_prioridad           ON crm_oportunidades (prioridad)",
            "CREATE INDEX idx_crm_proximo_contacto    ON crm_oportunidades (proximo_contacto)",
            "CREATE INDEX idx_crm_fecha_cambio_estado ON crm_oportunidades (fecha_cambio_estado)",
            "CREATE INDEX idx_crm_presupuesto         ON crm_oportunidades (presupuesto)",
        ],
    }


def build_crm_config_sla_schema():
    return {
        "name": "crm_config_sla",
        "type": "base",
        "fields": [
            {"name": "estado", "type": "text", "required": True, "presentable": True},
            {"name": "horas_limite", "type": "number", "required": True, "onlyInt": True},
        ],
        "listRule":   "@request.auth.id != ''",
        "viewRule":   "@request.auth.id != ''",
        "createRule": "@request.auth.role = 'admin'",
        "updateRule": "@request.auth.role = 'admin'",
        "deleteRule": "@request.auth.role = 'admin'",
        "indexes": [
            "CREATE UNIQUE INDEX idx_crm_config_sla_estado ON crm_config_sla (estado)",
        ],
    }


def build_crm_actividades_schema(crm_oportunidades_id, users_id):
    return {
        "name": "crm_actividades",
        "type": "base",
        "fields": [
            {"name": "oportunidad", "type": "relation", "required": True,
             "collectionId": crm_oportunidades_id, "maxSelect": 1, "cascadeDelete": True},
            {"name": "tipo",        "type": "select", "required": True,
             "values": ["creacion", "cambio_estado", "presupuesto_asociado", "comentario_usuario", "contacto", "otro"], "maxSelect": 1},
            {"name": "titulo",      "type": "text", "required": True, "max": 160},
            {"name": "descripcion", "type": "text", "required": False},
            {"name": "created_by",  "type": "relation", "required": False,
             "collectionId": users_id, "maxSelect": 1, "cascadeDelete": False},
        ],
        "listRule":   "@request.auth.id != ''",
        "viewRule":   "@request.auth.id != ''",
        "createRule": "@request.auth.id != ''",
        "updateRule": "@request.auth.id = created_by || @request.auth.role = 'admin'",
        "deleteRule": "@request.auth.id = created_by || @request.auth.role = 'admin'",
        "indexes": [
            "CREATE INDEX idx_crm_actividades_oportunidad ON crm_actividades (oportunidad)",
            "CREATE INDEX idx_crm_actividades_tipo        ON crm_actividades (tipo)",
        ],
    }


def upsert_record_by_estado(token, collection, estado, payload):
    existing = find_record(token, collection, f'estado = "{estado}"')
    if existing:
        code, data = req(
            "PATCH",
            f"/api/collections/{collection}/records/{existing['id']}",
            token=token,
            body=payload,
        )
        if code >= 300:
            print(f"  [warn] {collection}/{estado} seed update failed: {code} {data}")
        return
    code, data = req("POST", f"/api/collections/{collection}/records", token=token, body=payload)
    if code >= 300:
        print(f"  [warn] {collection}/{estado} seed create failed: {code} {data}")


# Pedido needs the clientes/users collection IDs for relation fields.
def build_pedidos_schema(clientes_id, users_id, presupuestos_id):
    return {
        "name": "pedidos",
        "type": "base",
        "fields": [
            {"name": "codigo",                   "type": "text",   "required": False, "max": 16, "presentable": True},
            {"name": "numero",                   "type": "number", "required": False, "onlyInt": True, "presentable": True},
            {"name": "referencia_odoo",          "type": "text",   "required": False, "max": 80},
            {"name": "presupuesto",              "type": "relation", "required": False,
             "collectionId": presupuestos_id, "maxSelect": 1, "cascadeDelete": False},
            {"name": "cliente",                  "type": "relation", "required": True,
             "collectionId": clientes_id, "maxSelect": 1, "cascadeDelete": False, "presentable": True},
            {"name": "fecha_creacion",           "type": "date",   "required": True},
            {"name": "fecha_entrega_estimada",   "type": "date",   "required": False},
            {"name": "fecha_entrega_hasta",      "type": "date",   "required": False},
            {"name": "total",                    "type": "number", "required": False},
            {"name": "pagado",                   "type": "number", "required": False},
            {"name": "senia",                    "type": "number", "required": False},
            {"name": "saldo",                    "type": "number", "required": False},
            {"name": "estado_pedido",            "type": "select", "required": True,
             "values": ["cargado", "en_produccion", "terminado", "entregado", "cancelado"], "maxSelect": 1},
            {"name": "estado_cortes",            "type": "select", "required": True,
             "values": ["pendiente", "en_corte", "cortados", "no_necesita"], "maxSelect": 1},
            {"name": "etapa_produccion",          "type": "select", "required": False,
             "values": ["pedido_nuevo", "para_medir", "para_cortar", "cortando", "cortado", "armando", "terminado", "para_instalar", "entregado_con_saldo", "entregado_sin_saldo"], "maxSelect": 1},
            {"name": "avisado_retiro",           "type": "bool",   "required": False},
            {"name": "hay_que_medir",            "type": "bool",   "required": False},
            {"name": "hay_que_enviar",           "type": "bool",   "required": False},
            {"name": "hay_que_instalar",         "type": "bool",   "required": False},
            {"name": "requiere_pintura",         "type": "bool",   "required": False},
            {"name": "descripcion",              "type": "editor", "required": False},
            {"name": "dibujo_json",              "type": "json",   "required": False, "maxSize": 2000000},
            {"name": "dibujo_png",               "type": "file",   "required": False, "maxSelect": 1, "maxSize": 10485760,
             "mimeTypes": ["image/png", "image/jpeg", "image/webp"]},
            {"name": "created_by",               "type": "relation", "required": False,
             "collectionId": users_id, "maxSelect": 1, "cascadeDelete": False},
            {"name": "cancelled_at",             "type": "date",   "required": False},
            {"name": "cancelled_reason",         "type": "text",   "required": False, "max": 500},
        ],
        # All authed users can read and create. Only admin can delete.
        "listRule":   "@request.auth.id != ''",
        "viewRule":   "@request.auth.id != ''",
        "createRule": "@request.auth.id != ''",
        # Update OK for both roles but empleado can't change estado_pedido to 'cancelado' (enforced in UI + hook if needed)
        "updateRule": "@request.auth.id != ''",
        "deleteRule": "@request.auth.role = 'admin'",
        "indexes": [
            "CREATE INDEX        idx_pedidos_codigo       ON pedidos (codigo)",
            "CREATE UNIQUE INDEX idx_pedidos_codigo_uq    ON pedidos (codigo) WHERE codigo != ''",
            "CREATE INDEX        idx_pedidos_numero       ON pedidos (numero)",
            "CREATE INDEX        idx_pedidos_ref_odoo     ON pedidos (referencia_odoo)",
            "CREATE INDEX        idx_pedidos_presupuesto  ON pedidos (presupuesto)",
            "CREATE UNIQUE INDEX idx_pedidos_presup_uq    ON pedidos (presupuesto) WHERE presupuesto != ''",
            "CREATE INDEX        idx_pedidos_cliente      ON pedidos (cliente)",
            "CREATE INDEX        idx_pedidos_estado_p     ON pedidos (estado_pedido)",
            "CREATE INDEX        idx_pedidos_estado_c     ON pedidos (estado_cortes)",
            "CREATE INDEX        idx_pedidos_etapa_prod   ON pedidos (etapa_produccion)",
            "CREATE INDEX        idx_pedidos_medir        ON pedidos (hay_que_medir)",
            "CREATE INDEX        idx_pedidos_enviar       ON pedidos (hay_que_enviar)",
            "CREATE INDEX        idx_pedidos_instalar     ON pedidos (hay_que_instalar)",
            "CREATE INDEX        idx_pedidos_fecha_crea   ON pedidos (fecha_creacion)",
            "CREATE INDEX        idx_pedidos_fecha_entrega ON pedidos (fecha_entrega_estimada)",
            "CREATE INDEX        idx_pedidos_fecha_hasta   ON pedidos (fecha_entrega_hasta)",
        ],
    }


PROVEEDORES_SCHEMA = {
    "name": "proveedores",
    "type": "base",
    "fields": [
        {"name": "nombre",    "type": "text",   "required": True,  "max": 160, "presentable": True},
        {"name": "rubro",     "type": "text",   "required": False, "max": 80},
        {"name": "telefono",  "type": "text",   "required": False, "max": 40},
        {"name": "direccion", "type": "text",   "required": False, "max": 240},
        {"name": "cuit",      "type": "text",   "required": False, "max": 20},
        {"name": "email",     "type": "email",  "required": False},
        {"name": "notas",     "type": "editor", "required": False},
        {"name": "activo",    "type": "bool",   "required": False},
    ],
    "listRule":   "@request.auth.role = 'admin'",
    "viewRule":   "@request.auth.role = 'admin'",
    "createRule": "@request.auth.role = 'admin'",
    "updateRule": "@request.auth.role = 'admin'",
    "deleteRule": "@request.auth.role = 'admin'",
    "indexes": [
        "CREATE INDEX idx_proveedores_nombre ON proveedores (nombre)",
        "CREATE INDEX idx_proveedores_rubro  ON proveedores (rubro)",
        "CREATE INDEX idx_proveedores_cuit   ON proveedores (cuit)",
    ],
}


PRODUCTOS_SCHEMA = {
    "name": "productos",
    "type": "base",
    "fields": [
        {"name": "nombre",              "type": "text",   "required": True,  "max": 180, "presentable": True},
        {"name": "referencia_interna",  "type": "text",   "required": False, "max": 60},
        {"name": "categoria",           "type": "text",   "required": False, "max": 160},
        {"name": "precio_venta",        "type": "number", "required": False},
        {"name": "cantidad_mano",       "type": "number", "required": False},
        {"name": "moneda",              "type": "text",   "required": False, "max": 12},
        {"name": "favorito",            "type": "bool",   "required": False},
        {"name": "activo",              "type": "bool",   "required": False},
        {"name": "source_ref",          "type": "text",   "required": False, "max": 120},
    ],
    "listRule":   "@request.auth.id != ''",
    "viewRule":   "@request.auth.id != ''",
    "createRule": "@request.auth.role = 'admin'",
    "updateRule": "@request.auth.role = 'admin'",
    "deleteRule": "@request.auth.role = 'admin'",
    "indexes": [
        "CREATE INDEX idx_productos_nombre ON productos (nombre)",
        "CREATE INDEX idx_productos_ref    ON productos (referencia_interna)",
        "CREATE INDEX idx_productos_cat    ON productos (categoria)",
    ],
}


def build_movimientos_schema(users_id, proveedores_id):
    return {
        "name": "movimientos",
        "type": "base",
        "fields": [
            {"name": "tipo",               "type": "select", "required": True,
             "values": ["ingreso", "egreso", "transferencia"], "maxSelect": 1},
            {"name": "monto",              "type": "number", "required": True},
            {"name": "cuenta",             "type": "text",   "required": True,  "max": 60},
            {"name": "cuenta_destino",     "type": "text",   "required": False, "max": 60},
            {"name": "detalle",            "type": "text",   "required": False, "max": 300},
            {"name": "categoria",          "type": "text",   "required": False, "max": 80},
            {"name": "proveedor",          "type": "relation", "required": False,
             "collectionId": proveedores_id, "maxSelect": 1, "cascadeDelete": False},
            {"name": "notas",              "type": "editor", "required": False},
            {"name": "numero_pedido",      "type": "text",   "required": False, "max": 20},
            {"name": "fecha",              "type": "text",   "required": True,  "max": 10},
            {"name": "check_odoo",         "type": "bool",   "required": False},
            {"name": "check_contabilidad", "type": "bool",   "required": False},
            {"name": "created_by",         "type": "relation", "required": False,
             "collectionId": users_id, "maxSelect": 1, "cascadeDelete": False},
        ],
        # Caja: solo admin
        "listRule":   "@request.auth.role = 'admin'",
        "viewRule":   "@request.auth.role = 'admin'",
        "createRule": "@request.auth.role = 'admin'",
        "updateRule": "@request.auth.role = 'admin'",
        "deleteRule": "@request.auth.role = 'admin'",
        "indexes": [
            "CREATE INDEX idx_mov_fecha ON movimientos (fecha)",
            "CREATE INDEX idx_mov_tipo  ON movimientos (tipo)",
            "CREATE INDEX idx_mov_categoria ON movimientos (categoria)",
            "CREATE INDEX idx_mov_proveedor ON movimientos (proveedor)",
        ],
    }


def build_pedido_items_schema(pedidos_id, presupuesto_items_id):
    return {
        "name": "pedido_items",
        "type": "base",
        "fields": [
            {"name": "pedido",           "type": "relation", "required": True,
             "collectionId": pedidos_id, "maxSelect": 1, "cascadeDelete": True, "presentable": True},
            {"name": "presupuesto_item", "type": "relation", "required": False,
             "collectionId": presupuesto_items_id, "maxSelect": 1, "cascadeDelete": False},
            {"name": "codigo",           "type": "text",   "required": False, "max": 100},
            {"name": "descripcion",      "type": "text",   "required": True, "max": 500, "presentable": True},
            {"name": "cantidad",         "type": "number", "required": True},
            {"name": "precio_unitario",  "type": "number", "required": True},
            {"name": "subtotal",         "type": "number", "required": False},
            {"name": "sort_order",       "type": "number", "required": False, "onlyInt": True},
        ],
        "listRule":   "@request.auth.id != ''",
        "viewRule":   "@request.auth.id != ''",
        "createRule": "@request.auth.id != ''",
        "updateRule": "@request.auth.id != ''",
        "deleteRule": "@request.auth.role = 'admin'",
        "indexes": [
            "CREATE INDEX idx_pedido_items_pedido      ON pedido_items (pedido)",
            "CREATE INDEX idx_pedido_items_sort_order  ON pedido_items (sort_order)",
        ],
    }


CUENTAS_SCHEMA = {
    "name": "cuentas",
    "type": "base",
    "fields": [
        {"name": "nombre",     "type": "text",   "required": True, "max": 60, "presentable": True},
        {"name": "activa",     "type": "bool",   "required": False},
        {"name": "saldo_inicial", "type": "number", "required": False},
        {"name": "fecha_saldo_inicial", "type": "date", "required": False},
        {"name": "sort_order", "type": "number", "required": False, "onlyInt": True},
    ],
    "listRule":   "@request.auth.id != ''",
    "viewRule":   "@request.auth.id != ''",
    "createRule": "@request.auth.role = 'admin'",
    "updateRule": "@request.auth.role = 'admin'",
    "deleteRule": "@request.auth.role = 'admin'",
    "indexes": [
        "CREATE UNIQUE INDEX idx_cuentas_nombre ON cuentas (nombre)",
        "CREATE INDEX idx_cuentas_activa        ON cuentas (activa)",
        "CREATE INDEX idx_cuentas_sort_order    ON cuentas (sort_order)",
    ],
}


def build_pagos_schema(clientes_id, presupuestos_id, pedidos_id, cuentas_id, movimientos_id, users_id):
    return {
        "name": "pagos",
        "type": "base",
        "fields": [
            {"name": "monto",       "type": "number", "required": True},
            {"name": "cuenta",      "type": "relation", "required": True,
             "collectionId": cuentas_id, "maxSelect": 1, "cascadeDelete": False, "presentable": True},
            {"name": "fecha",       "type": "date", "required": True},
            {"name": "cliente",     "type": "relation", "required": True,
             "collectionId": clientes_id, "maxSelect": 1, "cascadeDelete": False},
            {"name": "presupuesto", "type": "relation", "required": False,
             "collectionId": presupuestos_id, "maxSelect": 1, "cascadeDelete": False},
            {"name": "pedido",      "type": "relation", "required": False,
             "collectionId": pedidos_id, "maxSelect": 1, "cascadeDelete": False},
            {"name": "movimiento",  "type": "relation", "required": False,
             "collectionId": movimientos_id, "maxSelect": 1, "cascadeDelete": False},
            {"name": "nota",        "type": "text", "required": False, "max": 300},
            {"name": "created_by",  "type": "relation", "required": False,
             "collectionId": users_id, "maxSelect": 1, "cascadeDelete": False},
        ],
        # Money touches Caja, so admin-only for v1.
        "listRule":   "@request.auth.id != ''",
        "viewRule":   "@request.auth.id != ''",
        "createRule": "@request.auth.role = 'admin'",
        "updateRule": "@request.auth.role = 'admin'",
        "deleteRule": "@request.auth.role = 'admin'",
        "indexes": [
            "CREATE INDEX idx_pagos_fecha       ON pagos (fecha)",
            "CREATE INDEX idx_pagos_cliente     ON pagos (cliente)",
            "CREATE INDEX idx_pagos_presupuesto ON pagos (presupuesto)",
            "CREATE INDEX idx_pagos_pedido      ON pagos (pedido)",
            "CREATE INDEX idx_pagos_cuenta      ON pagos (cuenta)",
            "CREATE INDEX idx_pagos_movimiento  ON pagos (movimiento)",
        ],
    }


def build_chatwoot_conversations_schema(clientes_id, users_id):
    return {
        "name": "chatwoot_conversations",
        "type": "base",
        "fields": [
            {"name": "cliente", "type": "relation", "required": False,
             "collectionId": clientes_id, "maxSelect": 1, "cascadeDelete": False, "presentable": True},
            {"name": "conversation_id", "type": "text", "required": True, "max": 40, "presentable": True},
            {"name": "inbox_id", "type": "text", "required": False, "max": 40},
            {"name": "telefono", "type": "text", "required": False, "max": 40},
            {"name": "nombre", "type": "text", "required": False, "max": 160},
            {"name": "estado", "type": "select", "required": False,
             "values": ["abierta", "pendiente", "resuelta"], "maxSelect": 1},
            {"name": "url", "type": "url", "required": False},
            {"name": "ultima_actividad", "type": "date", "required": False},
            {"name": "notas", "type": "editor", "required": False},
            {"name": "created_by", "type": "relation", "required": False,
             "collectionId": users_id, "maxSelect": 1, "cascadeDelete": False},
        ],
        "listRule":   "@request.auth.id != ''",
        "viewRule":   "@request.auth.id != ''",
        "createRule": "@request.auth.id != ''",
        "updateRule": "@request.auth.id != ''",
        "deleteRule": "@request.auth.role = 'admin'",
        "indexes": [
            "CREATE UNIQUE INDEX idx_chatwoot_conversation_id ON chatwoot_conversations (conversation_id)",
            "CREATE INDEX idx_chatwoot_cliente ON chatwoot_conversations (cliente)",
            "CREATE INDEX idx_chatwoot_telefono ON chatwoot_conversations (telefono)",
            "CREATE INDEX idx_chatwoot_estado ON chatwoot_conversations (estado)",
        ],
    }


def build_corte_jobs_schema(pedidos_id):
    return {
        "name": "corte_jobs",
        "type": "base",
        "fields": [
            {"name": "pedido",        "type": "relation", "required": False,
             "collectionId": pedidos_id, "maxSelect": 1, "cascadeDelete": False, "presentable": True},
            {"name": "numero",        "type": "text",   "required": False, "max": 80, "presentable": True},
            {"name": "cliente_nombre","type": "text",   "required": False, "max": 160},
            {"name": "source",        "type": "select", "required": True,
             "values": ["pedido", "legacy", "manual"], "maxSelect": 1},
            {"name": "legacy_job_id", "type": "text",   "required": False, "max": 80},
            {"name": "archived",      "type": "bool",   "required": False},
            {"name": "sort_order",    "type": "number", "required": False, "onlyInt": True},
        ],
        "listRule":   "@request.auth.id != ''",
        "viewRule":   "@request.auth.id != ''",
        "createRule": "@request.auth.id != ''",
        "updateRule": "@request.auth.id != ''",
        "deleteRule": "@request.auth.role = 'admin'",
        "indexes": [
            "CREATE INDEX idx_corte_jobs_pedido        ON corte_jobs (pedido)",
            "CREATE INDEX idx_corte_jobs_numero        ON corte_jobs (numero)",
            "CREATE INDEX idx_corte_jobs_source        ON corte_jobs (source)",
            "CREATE INDEX idx_corte_jobs_legacy_job_id ON corte_jobs (legacy_job_id)",
            "CREATE INDEX idx_corte_jobs_archived      ON corte_jobs (archived)",
            "CREATE INDEX idx_corte_jobs_sort_order    ON corte_jobs (sort_order)",
        ],
    }


def build_corte_items_schema(corte_jobs_id):
    return {
        "name": "corte_items",
        "type": "base",
        "fields": [
            {"name": "job",               "type": "relation", "required": True,
             "collectionId": corte_jobs_id, "maxSelect": 1, "cascadeDelete": True, "presentable": True},
            {"name": "legacy_item_id",    "type": "text",   "required": False, "max": 80},
            {"name": "cantidad",          "type": "number", "required": True,  "onlyInt": True},
            {"name": "ancho",             "type": "number", "required": False},
            {"name": "alto",              "type": "number", "required": False},
            {"name": "material",          "type": "text",   "required": True,  "max": 32, "presentable": True},
            {"name": "color",             "type": "text",   "required": False, "max": 80},
            {"name": "canto_ancho",       "type": "number", "required": False, "onlyInt": True},
            {"name": "canto_alto",        "type": "number", "required": False, "onlyInt": True},
            {"name": "veta",              "type": "select", "required": True,
             "values": ["ninguna", "ancho", "alto"], "maxSelect": 1},
            {"name": "nota",              "type": "text",   "required": False, "max": 500},
            {"name": "estado",            "type": "select", "required": True,
             "values": ["pendiente", "cortado"], "maxSelect": 1},
            {"name": "canto_ancho_hecho", "type": "number", "required": False, "onlyInt": True},
            {"name": "canto_alto_hecho",  "type": "number", "required": False, "onlyInt": True},
            {"name": "sort_order",        "type": "number", "required": False, "onlyInt": True},
        ],
        "listRule":   "@request.auth.id != ''",
        "viewRule":   "@request.auth.id != ''",
        "createRule": "@request.auth.id != ''",
        "updateRule": "@request.auth.id != ''",
        "deleteRule": "@request.auth.id != ''",
        "indexes": [
            "CREATE INDEX idx_corte_items_job        ON corte_items (job)",
            "CREATE INDEX idx_corte_items_material   ON corte_items (material)",
            "CREATE INDEX idx_corte_items_estado     ON corte_items (estado)",
            "CREATE INDEX idx_corte_items_sort_order ON corte_items (sort_order)",
        ],
    }


PRECIOS_SCHEMA = {
    "name": "precios",
    "type": "base",
    "fields": [
        {"name": "data", "type": "json", "required": False, "maxSize": 500000},
    ],
    # Only authenticated users can read; only admin can write.
    "listRule":   "@request.auth.id != ''",
    "viewRule":   "@request.auth.id != ''",
    "createRule": "@request.auth.role = 'admin'",
    "updateRule": "@request.auth.role = 'admin'",
    "deleteRule": "@request.auth.role = 'admin'",
}


CATEGORIAS_SCHEMA = {
    "name": "categorias",
    "type": "base",
    "fields": [
        {"name": "nombre",     "type": "text", "required": True, "max": 120, "presentable": True},
        {"name": "parent",     "type": "relation", "required": False, "collectionId": "categorias", "maxSelect": 1, "cascadeDelete": True, "presentable": True},
        {"name": "sort_order", "type": "number", "required": False, "onlyInt": True},
        {"name": "activa",     "type": "bool", "required": False},
    ],
    "listRule":   "@request.auth.id != ''",
    "viewRule":   "@request.auth.id != ''",
    "createRule": "@request.auth.role = 'admin'",
    "updateRule": "@request.auth.role = 'admin'",
    "deleteRule": "@request.auth.role = 'admin'",
    "indexes": [
        "CREATE INDEX idx_categorias_nombre     ON categorias (nombre)",
        "CREATE INDEX idx_categorias_parent     ON categorias (parent)",
        "CREATE INDEX idx_categorias_sort_order ON categorias (sort_order)",
    ],
}


def build_tareas_schema(pedidos_id, users_id):
    return {
        "name": "tareas",
        "type": "base",
        "fields": [
            {"name": "titulo",      "type": "text",   "required": True,  "max": 200, "presentable": True},
            {"name": "tipo",        "type": "select", "required": True,
             "values": ["medir", "comprar", "cortar", "armar", "instalar", "entregar", "llamar", "otra"], "maxSelect": 1},
            {"name": "descripcion", "type": "editor", "required": False},
            {"name": "fecha",       "type": "text",   "required": False, "max": 10},
            {"name": "hora",        "type": "text",   "required": False, "max": 5},
            {"name": "pedido",      "type": "relation", "required": False,
             "collectionId": pedidos_id, "maxSelect": 1, "cascadeDelete": False, "presentable": True},
            {"name": "estado",      "type": "select", "required": True,
             "values": ["pendiente", "hecha"], "maxSelect": 1},
            {"name": "prioridad",   "type": "select", "required": False,
             "values": ["baja", "media", "alta"], "maxSelect": 1},
            {"name": "asignado_a",  "type": "relation", "required": False,
             "collectionId": users_id, "maxSelect": 1, "cascadeDelete": False},
            {"name": "recordatorio_wa", "type": "bool", "required": False},
            {"name": "completada_at",   "type": "date", "required": False},
            {"name": "created_by",  "type": "relation", "required": False,
             "collectionId": users_id, "maxSelect": 1, "cascadeDelete": False},
        ],
        "listRule":   "@request.auth.id != ''",
        "viewRule":   "@request.auth.id != ''",
        "createRule": "@request.auth.id != ''",
        "updateRule": "@request.auth.id != ''",
        "deleteRule": "@request.auth.id != ''",
        "indexes": [
            "CREATE INDEX idx_tareas_estado   ON tareas (estado)",
            "CREATE INDEX idx_tareas_fecha    ON tareas (fecha)",
            "CREATE INDEX idx_tareas_pedido   ON tareas (pedido)",
            "CREATE INDEX idx_tareas_tipo     ON tareas (tipo)",
            "CREATE INDEX idx_tareas_asignado ON tareas (asignado_a)",
        ],
    }


def main():
    print(f"== Fibromuebles-Apps schema ==  PB={PB_URL}")
    token = auth_admin()
    print("Authed as admin OK")
    print("Creating/updating collections:")
    users_id = upsert_collection(token, USERS_SCHEMA)
    upsert_collection(token, OTP_CODES_SCHEMA)
    upsert_collection(token, build_user_permissions_schema(users_id))
    clientes_id = upsert_collection(token, CLIENTES_SCHEMA)
    upsert_collection(token, PRESUPUESTO_COUNTERS_SCHEMA)
    presupuestos_id = upsert_collection(token, build_presupuestos_schema(clientes_id, users_id))
    presupuesto_items_id = upsert_collection(token, build_presupuesto_items_schema(presupuestos_id))
    crm_oportunidades_id = upsert_collection(token, build_crm_oportunidades_schema(clientes_id, presupuestos_id, users_id))
    upsert_collection(token, build_crm_config_sla_schema())
    upsert_collection(token, build_crm_actividades_schema(crm_oportunidades_id, users_id))
    upsert_collection(token, build_chatwoot_conversations_schema(clientes_id, users_id))
    pedidos_id = upsert_collection(token, build_pedidos_schema(clientes_id, users_id, presupuestos_id))
    upsert_collection(token, build_pedido_items_schema(pedidos_id, presupuesto_items_id))
    upsert_collection(token, build_tareas_schema(pedidos_id, users_id))
    upsert_collection(token, PRODUCTOS_SCHEMA)
    categorias_existing = find_collection(token, "categorias")
    if categorias_existing:
        CATEGORIAS_SCHEMA["fields"][1]["collectionId"] = categorias_existing["id"]
    upsert_collection(token, CATEGORIAS_SCHEMA)
    corte_jobs_id = upsert_collection(token, build_corte_jobs_schema(pedidos_id))
    upsert_collection(token, build_corte_items_schema(corte_jobs_id))
    proveedores_id = upsert_collection(token, PROVEEDORES_SCHEMA)
    movimientos_id = upsert_collection(token, build_movimientos_schema(users_id, proveedores_id))
    cuentas_id = upsert_collection(token, CUENTAS_SCHEMA)
    upsert_collection(token, build_pagos_schema(
        clientes_id, presupuestos_id, pedidos_id, cuentas_id, movimientos_id, users_id))
    upsert_collection(token, PRECIOS_SCHEMA)
    
    print("Seeding CRM SLAs:")
    default_slas = {
        "nuevo": 24,
        "contactado": 48,
        "presupuestar": 48,
        "presupuestado": 72,
        "propuesta_enviada": 72,
        "recalcular_presupuesto": 24,
        "consulta_analisis": 48,
        "ultima_oportunidad": 48,
        "sin_respuesta": 168,
    }
    for estado, horas in default_slas.items():
        upsert_record_by_estado(token, "crm_config_sla", estado, {
            "estado": estado,
            "horas_limite": horas
        })

    print("Seeding accounts:")
    for i, name in enumerate(["Efectivo", "Banco Macro", "Cuenta DNI", "Banco Nación", "Cocos", "Mercadopago"]):
        upsert_record_by_name(token, "cuentas", name, {
            "nombre": name,
            "activa": True,
            "saldo_inicial": 0,
            "sort_order": i,
        })
    print("Done.")


if __name__ == "__main__":
    main()
