-- =============================================================================
-- MICHANGARRITO - 15 INVOICES (SAT/CFDI)
-- =============================================================================
-- Facturacion electronica mexicana (CFDI)
-- =============================================================================

-- Crear schema si no existe
CREATE SCHEMA IF NOT EXISTS billing;

-- Configuracion fiscal por tenant
CREATE TABLE IF NOT EXISTS billing.tax_configs (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,

    -- Datos fiscales del emisor
    rfc VARCHAR(13) NOT NULL,
    razon_social VARCHAR(200) NOT NULL,
    regimen_fiscal VARCHAR(3) NOT NULL,
    codigo_postal VARCHAR(5) NOT NULL,

    -- Certificado digital (CSD)
    csd_certificate TEXT,
    csd_private_key_encrypted TEXT,
    csd_password_encrypted TEXT,
    csd_valid_from TIMESTAMPTZ,
    csd_valid_to TIMESTAMPTZ,

    -- PAC Provider
    pac_provider VARCHAR(20) DEFAULT 'facturapi',
    pac_api_key_encrypted TEXT,
    pac_sandbox BOOLEAN DEFAULT true,

    -- Configuracion
    serie VARCHAR(10) DEFAULT 'A',
    folio_actual INTEGER DEFAULT 1,
    auto_send_email BOOLEAN DEFAULT true,
    logo_url TEXT,

    status VARCHAR(20) DEFAULT 'pending',
    -- pending, active, suspended

    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(tenant_id)
);

CREATE INDEX idx_tax_configs_tenant ON billing.tax_configs(tenant_id);
CREATE INDEX idx_tax_configs_rfc ON billing.tax_configs(rfc);

CREATE TRIGGER update_tax_configs_updated_at
    BEFORE UPDATE ON billing.tax_configs
    FOR EACH ROW EXECUTE FUNCTION update_updated_at();

-- Facturas (CFDI)
CREATE TABLE IF NOT EXISTS billing.invoices (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
    sale_id UUID REFERENCES sales.sales(id),

    -- Tipo de comprobante
    tipo_comprobante VARCHAR(1) NOT NULL DEFAULT 'I',
    -- I = Ingreso, E = Egreso, T = Traslado, P = Pago, N = Nomina

    -- Folio fiscal
    uuid VARCHAR(36) UNIQUE,
    serie VARCHAR(10),
    folio INTEGER,

    -- Receptor (cliente)
    receptor_rfc VARCHAR(13) NOT NULL,
    receptor_nombre VARCHAR(200) NOT NULL,
    receptor_regimen_fiscal VARCHAR(3),
    receptor_codigo_postal VARCHAR(5) NOT NULL,
    receptor_uso_cfdi VARCHAR(4) NOT NULL,
    receptor_email VARCHAR(200),

    -- Montos
    subtotal DECIMAL(12,2) NOT NULL,
    descuento DECIMAL(12,2) DEFAULT 0,
    total_impuestos_trasladados DECIMAL(12,2) DEFAULT 0,
    total_impuestos_retenidos DECIMAL(12,2) DEFAULT 0,
    total DECIMAL(12,2) NOT NULL,

    -- Pago
    forma_pago VARCHAR(2) NOT NULL,
    metodo_pago VARCHAR(3) NOT NULL,
    condiciones_pago VARCHAR(100),

    -- Moneda
    moneda VARCHAR(3) DEFAULT 'MXN',
    tipo_cambio DECIMAL(10,6) DEFAULT 1,

    -- Archivos
    xml_url TEXT,
    pdf_url TEXT,
    qr_url TEXT,

    -- Estado
    status VARCHAR(20) DEFAULT 'draft',
    -- draft, pending, stamped, sent, cancelled

    -- Cancelacion
    cancelled_at TIMESTAMPTZ,
    cancel_reason VARCHAR(2),
    cancel_uuid_replacement VARCHAR(36),

    -- Timbrado
    stamped_at TIMESTAMPTZ,
    pac_response JSONB,

    -- Metadata
    notes TEXT,

    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_invoices_tenant ON billing.invoices(tenant_id);
CREATE INDEX idx_invoices_sale ON billing.invoices(sale_id);
CREATE INDEX idx_invoices_uuid ON billing.invoices(uuid);
CREATE INDEX idx_invoices_receptor ON billing.invoices(receptor_rfc);
CREATE INDEX idx_invoices_status ON billing.invoices(status);
CREATE INDEX idx_invoices_date ON billing.invoices(created_at);

CREATE TRIGGER update_invoices_updated_at
    BEFORE UPDATE ON billing.invoices
    FOR EACH ROW EXECUTE FUNCTION update_updated_at();

-- Conceptos de factura
CREATE TABLE IF NOT EXISTS billing.invoice_items (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    invoice_id UUID NOT NULL REFERENCES billing.invoices(id) ON DELETE CASCADE,
    product_id UUID REFERENCES catalog.products(id),

    -- Clave producto/servicio SAT
    clave_prod_serv VARCHAR(8) NOT NULL,
    no_identificacion VARCHAR(100),

    -- Descripcion
    descripcion VARCHAR(1000) NOT NULL,

    -- Cantidad
    cantidad DECIMAL(12,6) NOT NULL,
    clave_unidad VARCHAR(3) NOT NULL,
    unidad VARCHAR(20),

    -- Precios
    valor_unitario DECIMAL(12,6) NOT NULL,
    descuento DECIMAL(12,2) DEFAULT 0,
    importe DECIMAL(12,2) NOT NULL,

    -- Objeto de impuesto
    objeto_imp VARCHAR(2) DEFAULT '02',

    created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_invoice_items_invoice ON billing.invoice_items(invoice_id);

-- Impuestos de conceptos
CREATE TABLE IF NOT EXISTS billing.invoice_item_taxes (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    invoice_item_id UUID NOT NULL REFERENCES billing.invoice_items(id) ON DELETE CASCADE,

    tipo VARCHAR(10) NOT NULL,
    -- traslado, retencion

    impuesto VARCHAR(3) NOT NULL,
    -- 001 = ISR, 002 = IVA, 003 = IEPS

    tipo_factor VARCHAR(10) NOT NULL,
    -- Tasa, Cuota, Exento

    tasa_o_cuota DECIMAL(10,6),
    base DECIMAL(12,2) NOT NULL,
    importe DECIMAL(12,2),

    created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_invoice_item_taxes_item ON billing.invoice_item_taxes(invoice_item_id);

-- Historial de facturas (para auditoria)
CREATE TABLE IF NOT EXISTS billing.invoice_history (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    invoice_id UUID NOT NULL REFERENCES billing.invoices(id) ON DELETE CASCADE,

    action VARCHAR(20) NOT NULL,
    -- created, stamped, sent, cancelled

    details JSONB,
    performed_by UUID,

    created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_invoice_history_invoice ON billing.invoice_history(invoice_id);

-- Funcion para obtener siguiente folio
CREATE OR REPLACE FUNCTION get_next_invoice_folio(p_tenant_id UUID, p_serie VARCHAR DEFAULT 'A')
RETURNS INTEGER AS $$
DECLARE
    next_folio INTEGER;
BEGIN
    UPDATE billing.tax_configs
    SET folio_actual = folio_actual + 1
    WHERE tenant_id = p_tenant_id
    RETURNING folio_actual INTO next_folio;

    IF next_folio IS NULL THEN
        next_folio := 1;
    END IF;

    RETURN next_folio;
END;
$$ LANGUAGE plpgsql;

-- Funcion para obtener resumen de facturacion
CREATE OR REPLACE FUNCTION get_invoice_summary(p_tenant_id UUID, p_month DATE DEFAULT CURRENT_DATE)
RETURNS TABLE (
    total_invoices INTEGER,
    total_amount DECIMAL(12,2),
    total_cancelled INTEGER,
    by_status JSONB
) AS $$
BEGIN
    RETURN QUERY
    SELECT
        COUNT(*)::INTEGER as total_invoices,
        COALESCE(SUM(total), 0) as total_amount,
        COUNT(*) FILTER (WHERE status = 'cancelled')::INTEGER as total_cancelled,
        jsonb_object_agg(status, cnt) as by_status
    FROM (
        SELECT status, COUNT(*) as cnt
        FROM billing.invoices
        WHERE tenant_id = p_tenant_id
        AND DATE_TRUNC('month', created_at) = DATE_TRUNC('month', p_month)
        GROUP BY status
    ) s,
    billing.invoices i
    WHERE i.tenant_id = p_tenant_id
    AND DATE_TRUNC('month', i.created_at) = DATE_TRUNC('month', p_month);
END;
$$ LANGUAGE plpgsql;
