-- =============================================================
-- ARCHIVO: 12-payment-terminals.sql
-- DESCRIPCION: Terminales de pago TPV (MercadoPago, Clip)
-- VERSION: 1.0.0
-- PROYECTO: ERP-Mecanicas-Diesel
-- FECHA: 2026-01-25
-- PROPAGADO DESDE: erp-core v1.5.0 (PROP-CORE-004)
-- =============================================================
-- Uso: Cobro de servicios, venta refacciones mostrador
-- =============================================================

-- =====================
-- SCHEMA: payment_terminals
-- =====================
CREATE SCHEMA IF NOT EXISTS payment_terminals;

-- =====================
-- ENUMS
-- =====================
DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'terminal_provider') THEN
        CREATE TYPE payment_terminals.terminal_provider AS ENUM (
            'mercadopago',
            'clip',
            'stripe_terminal'
        );
    END IF;
END$$;

DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'terminal_payment_status') THEN
        CREATE TYPE payment_terminals.terminal_payment_status AS ENUM (
            'pending',
            'processing',
            'approved',
            'authorized',
            'in_process',
            'rejected',
            'refunded',
            'partially_refunded',
            'cancelled',
            'charged_back'
        );
    END IF;
END$$;

DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'payment_method_type') THEN
        CREATE TYPE payment_terminals.payment_method_type AS ENUM (
            'card',
            'qr',
            'link',
            'cash',
            'bank_transfer'
        );
    END IF;
END$$;

-- =====================
-- TABLA: tenant_terminal_configs
-- =====================
CREATE TABLE IF NOT EXISTS payment_terminals.tenant_terminal_configs (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
    provider payment_terminals.terminal_provider NOT NULL,
    name VARCHAR(100) NOT NULL,
    credentials JSONB NOT NULL DEFAULT '{}',
    config JSONB DEFAULT '{}',
    is_active BOOLEAN DEFAULT true,
    is_verified BOOLEAN DEFAULT false,
    verification_error TEXT,
    verified_at TIMESTAMPTZ,
    daily_limit DECIMAL(12,2),
    monthly_limit DECIMAL(12,2),
    transaction_limit DECIMAL(12,2),
    webhook_url VARCHAR(500),
    webhook_secret VARCHAR(255),
    metadata JSONB DEFAULT '{}',
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    created_by UUID REFERENCES auth.users(id),
    UNIQUE(tenant_id, provider, name)
);

-- =====================
-- TABLA: terminal_payments
-- =====================
CREATE TABLE IF NOT EXISTS payment_terminals.terminal_payments (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
    config_id UUID REFERENCES payment_terminals.tenant_terminal_configs(id),
    branch_terminal_id UUID,
    provider payment_terminals.terminal_provider NOT NULL,
    external_id VARCHAR(255),
    external_status VARCHAR(50),
    amount DECIMAL(12,2) NOT NULL,
    currency VARCHAR(3) DEFAULT 'MXN',
    status payment_terminals.terminal_payment_status DEFAULT 'pending',
    payment_method payment_terminals.payment_method_type DEFAULT 'card',
    card_last_four VARCHAR(4),
    card_brand VARCHAR(20),
    card_type VARCHAR(20),
    customer_email VARCHAR(255),
    customer_phone VARCHAR(20),
    customer_name VARCHAR(200),
    description TEXT,
    statement_descriptor VARCHAR(50),
    reference_type VARCHAR(50),
    reference_id UUID,
    fee_amount DECIMAL(10,4),
    fee_details JSONB,
    net_amount DECIMAL(12,2),
    refunded_amount DECIMAL(12,2) DEFAULT 0,
    refund_reason TEXT,
    provider_response JSONB,
    error_code VARCHAR(50),
    error_message TEXT,
    processed_at TIMESTAMPTZ,
    refunded_at TIMESTAMPTZ,
    metadata JSONB DEFAULT '{}',
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    created_by UUID REFERENCES auth.users(id)
);

-- =====================
-- TABLA: terminal_webhook_events
-- =====================
CREATE TABLE IF NOT EXISTS payment_terminals.terminal_webhook_events (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id),
    provider payment_terminals.terminal_provider NOT NULL,
    event_type VARCHAR(100) NOT NULL,
    event_id VARCHAR(255),
    payment_id UUID REFERENCES payment_terminals.terminal_payments(id),
    external_id VARCHAR(255),
    payload JSONB NOT NULL,
    headers JSONB,
    signature_valid BOOLEAN,
    processed BOOLEAN DEFAULT false,
    processed_at TIMESTAMPTZ,
    processing_error TEXT,
    retry_count INTEGER DEFAULT 0,
    idempotency_key VARCHAR(255),
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(provider, event_id)
);

-- =====================
-- TABLA: terminal_retry_queue
-- =====================
CREATE TABLE IF NOT EXISTS payment_terminals.terminal_retry_queue (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id),
    payment_id UUID REFERENCES payment_terminals.terminal_payments(id),
    provider payment_terminals.terminal_provider NOT NULL,
    operation VARCHAR(50) NOT NULL,
    payload JSONB NOT NULL,
    attempts INTEGER DEFAULT 0,
    max_attempts INTEGER DEFAULT 5,
    next_retry_at TIMESTAMPTZ,
    last_error TEXT,
    last_error_code VARCHAR(50),
    status VARCHAR(20) DEFAULT 'pending',
    completed_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

-- =====================
-- TABLA: terminal_payment_links
-- =====================
CREATE TABLE IF NOT EXISTS payment_terminals.terminal_payment_links (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
    config_id UUID REFERENCES payment_terminals.tenant_terminal_configs(id),
    provider payment_terminals.terminal_provider NOT NULL,
    external_id VARCHAR(255),
    url VARCHAR(1000) NOT NULL,
    short_url VARCHAR(500),
    amount DECIMAL(12,2) NOT NULL,
    currency VARCHAR(3) DEFAULT 'MXN',
    title VARCHAR(200),
    description TEXT,
    status VARCHAR(30) DEFAULT 'active',
    payment_id UUID REFERENCES payment_terminals.terminal_payments(id),
    expires_at TIMESTAMPTZ,
    reference_type VARCHAR(50),
    reference_id UUID,
    metadata JSONB DEFAULT '{}',
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    created_by UUID REFERENCES auth.users(id)
);

-- =====================
-- INDICES
-- =====================
CREATE INDEX IF NOT EXISTS idx_terminal_configs_tenant ON payment_terminals.tenant_terminal_configs(tenant_id);
CREATE INDEX IF NOT EXISTS idx_terminal_configs_provider ON payment_terminals.tenant_terminal_configs(provider);
CREATE INDEX IF NOT EXISTS idx_terminal_payments_tenant ON payment_terminals.terminal_payments(tenant_id);
CREATE INDEX IF NOT EXISTS idx_terminal_payments_status ON payment_terminals.terminal_payments(status);
CREATE INDEX IF NOT EXISTS idx_terminal_payments_external ON payment_terminals.terminal_payments(external_id);
CREATE INDEX IF NOT EXISTS idx_terminal_payments_reference ON payment_terminals.terminal_payments(reference_type, reference_id);
CREATE INDEX IF NOT EXISTS idx_webhook_events_tenant ON payment_terminals.terminal_webhook_events(tenant_id);
CREATE INDEX IF NOT EXISTS idx_webhook_events_processed ON payment_terminals.terminal_webhook_events(processed, created_at) WHERE processed = false;
CREATE INDEX IF NOT EXISTS idx_retry_queue_next ON payment_terminals.terminal_retry_queue(next_retry_at) WHERE status = 'pending';
CREATE INDEX IF NOT EXISTS idx_payment_links_tenant ON payment_terminals.terminal_payment_links(tenant_id);
CREATE INDEX IF NOT EXISTS idx_payment_links_status ON payment_terminals.terminal_payment_links(status);

-- =====================
-- RLS POLICIES
-- =====================
ALTER TABLE payment_terminals.tenant_terminal_configs ENABLE ROW LEVEL SECURITY;
ALTER TABLE payment_terminals.terminal_payments ENABLE ROW LEVEL SECURITY;
ALTER TABLE payment_terminals.terminal_webhook_events ENABLE ROW LEVEL SECURITY;
ALTER TABLE payment_terminals.terminal_retry_queue ENABLE ROW LEVEL SECURITY;
ALTER TABLE payment_terminals.terminal_payment_links ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_configs_isolation ON payment_terminals.tenant_terminal_configs
    USING (tenant_id = current_setting('app.current_tenant', true)::UUID);
CREATE POLICY terminal_payments_isolation ON payment_terminals.terminal_payments
    USING (tenant_id = current_setting('app.current_tenant', true)::UUID);
CREATE POLICY webhook_events_isolation ON payment_terminals.terminal_webhook_events
    USING (tenant_id = current_setting('app.current_tenant', true)::UUID);
CREATE POLICY retry_queue_isolation ON payment_terminals.terminal_retry_queue
    USING (tenant_id = current_setting('app.current_tenant', true)::UUID);
CREATE POLICY payment_links_isolation ON payment_terminals.terminal_payment_links
    USING (tenant_id = current_setting('app.current_tenant', true)::UUID);

-- =====================
-- FUNCIONES
-- =====================
CREATE OR REPLACE FUNCTION payment_terminals.calculate_next_retry(
    p_attempts INTEGER,
    p_base_delay_seconds INTEGER DEFAULT 60
) RETURNS TIMESTAMPTZ AS $$
BEGIN
    RETURN NOW() + (p_base_delay_seconds * POWER(2, p_attempts)) * INTERVAL '1 second';
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION payment_terminals.expire_old_pending_payments()
RETURNS INTEGER AS $$
DECLARE
    affected_rows INTEGER;
BEGIN
    UPDATE payment_terminals.terminal_payments
    SET status = 'cancelled', updated_at = NOW(), error_message = 'Payment expired'
    WHERE status = 'pending' AND created_at < NOW() - INTERVAL '24 hours';
    GET DIAGNOSTICS affected_rows = ROW_COUNT;
    RETURN affected_rows;
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION payment_terminals.expire_payment_links()
RETURNS INTEGER AS $$
DECLARE
    affected_rows INTEGER;
BEGIN
    UPDATE payment_terminals.terminal_payment_links
    SET status = 'expired', updated_at = NOW()
    WHERE status = 'active' AND expires_at IS NOT NULL AND expires_at < NOW();
    GET DIAGNOSTICS affected_rows = ROW_COUNT;
    RETURN affected_rows;
END;
$$ LANGUAGE plpgsql;

COMMENT ON SCHEMA payment_terminals IS 'Terminales de pago TPV - Mecanicas Diesel';
-- =============================================================
-- FIN DEL ARCHIVO
-- =============================================================
