# Prescription Composer - Seleção Composicional de Medicamentos

> Padrão de refinamento progressivo para prescrição de medicamentos

---

## Conceito

O usuário constrói a prescrição através de seleções progressivas onde cada escolha filtra as opções seguintes:

```
Substância/Produto → Forma → Concentração → Apresentação → Posologia
```

Cada passo mostra apenas opções válidas baseadas nas seleções anteriores.

---

## Fluxo de Seleção

### Passo 1: Busca inicial

O usuário digita nome comercial ou substância:

```
┌─────────────────────────────────────┐
│ 🔍 Buscar medicamento...            │
│                                     │
│   "tylenol"                         │
│   "paracetamol"                     │
│   "amoxicilina"                     │
└─────────────────────────────────────┘
```

### Passo 2: Formas farmacêuticas disponíveis

Após selecionar, mostra formas disponíveis como drops:

```
┌─────────────────────────────────────┐
│ Tylenol (Paracetamol)               │
│                                     │
│ Forma farmacêutica:                 │
│ ┌──────────┐ ┌──────────┐ ┌───────┐ │
│ │comprimido│ │cápsula   │ │gotas  │ │
│ └──────────┘ │mole      │ └───────┘ │
│              └──────────┘           │
└─────────────────────────────────────┘
```

### Passo 3: Concentrações disponíveis

Baseado na forma selecionada:

```
┌─────────────────────────────────────┐
│ Tylenol (Paracetamol)               │
│ Forma: comprimido ✓                 │
│                                     │
│ Concentração:                       │
│ ┌────────┐ ┌────────┐ ┌──────────┐  │
│ │ 500mg  │ │ 750mg  │ │ 1000mg   │  │
│ └────────┘ └────────┘ └──────────┘  │
└─────────────────────────────────────┘
```

Ou para gotas:

```
┌─────────────────────────────────────┐
│ Tylenol (Paracetamol)               │
│ Forma: gotas ✓                      │
│                                     │
│ Concentração:                       │
│ ┌────────────┐                      │
│ │ 200mg/mL   │                      │
│ └────────────┘                      │
└─────────────────────────────────────┘
```

### Passo 4: Apresentações disponíveis

```
┌─────────────────────────────────────┐
│ Tylenol 750mg comprimido ✓          │
│                                     │
│ Apresentação:                       │
│ ┌────────────┐ ┌────────────┐       │
│ │ cx 20 cp   │ │ cx 10 cp   │       │
│ └────────────┘ └────────────┘       │
└─────────────────────────────────────┘
```

### Passo 5: Posologia

```
┌─────────────────────────────────────┐
│ Tylenol 750mg comprimido cx 20 ✓    │
│                                     │
│ Posologia:                          │
│ ┌───┐ comprimido(s)                 │
│ │ 1 │                               │
│ └───┘                               │
│ de ┌───┐/┌───┐ horas                │
│    │ 6 │ │ 6 │                      │
│    └───┘ └───┘                      │
│ por ┌───┐ dias                      │
│     │ 5 │                           │
│     └───┘                           │
│                                     │
│ [ ] Se necessário                   │
│ [ ] Uso contínuo                    │
└─────────────────────────────────────┘
```

---

## Implementação

### HTML + HTMX

```html
<div class="prescription-composer" id="rx-composer">

    <!-- Passo 1: Busca -->
    <div class="composer-step" data-step="search">
        <label class="step-label">Medicamento</label>
        <div class="search-container">
            <input type="text"
                   class="search-input"
                   name="query"
                   placeholder="Buscar por nome comercial ou substância..."
                   hx-get="/rx/search"
                   hx-trigger="keyup changed delay:300ms"
                   hx-target="#search-results"
                   autocomplete="off" />
            <div id="search-results" class="search-results"></div>
        </div>
    </div>

    <!-- Passo 2: Forma farmacêutica -->
    <div class="composer-step hidden" data-step="form" id="step-form">
        <label class="step-label">Forma farmacêutica</label>
        <div class="options-grid" id="form-options">
            <!-- Carregado via HTMX após seleção do produto -->
        </div>
    </div>

    <!-- Passo 3: Concentração -->
    <div class="composer-step hidden" data-step="strength" id="step-strength">
        <label class="step-label">Concentração</label>
        <div class="options-grid" id="strength-options">
            <!-- Carregado via HTMX após seleção da forma -->
        </div>
    </div>

    <!-- Passo 4: Apresentação -->
    <div class="composer-step hidden" data-step="presentation" id="step-presentation">
        <label class="step-label">Apresentação</label>
        <div class="options-grid" id="presentation-options">
            <!-- Carregado via HTMX após seleção da concentração -->
        </div>
    </div>

    <!-- Passo 5: Posologia -->
    <div class="composer-step hidden" data-step="dosage" id="step-dosage">
        <label class="step-label">Posologia</label>
        <div class="dosage-composer" id="dosage-options">
            <!-- Carregado via HTMX após seleção da apresentação -->
        </div>
    </div>

    <!-- Preview da prescrição -->
    <div class="composer-preview" id="rx-preview">
        <label class="preview-label">
            <i class="fas fa-prescription mr-2"></i>Prescrição
        </label>
        <div class="preview-content">
            <!-- Atualizado em tempo real -->
        </div>
    </div>

</div>
```

### Partial: Opções de forma farmacêutica

```html
<!-- /rx/forms/{product_id} -->
<div class="options-grid">
    {% for form in forms %}
    <button type="button"
            class="option-drop drop-fofa"
            hx-get="/rx/strengths/{{ product_id }}/{{ form.id }}"
            hx-target="#strength-options"
            hx-swap="innerHTML"
            onclick="selectOption(this, 'form', '{{ form.name }}')"
            data-value="{{ form.id }}">
        {{ form.name }}
    </button>
    {% endfor %}
</div>

<script>
    // Revelar próximo passo
    document.getElementById('step-strength').classList.remove('hidden');
</script>
```

### Partial: Composição de posologia

```html
<!-- /rx/dosage/{product_id} -->
<div class="dosage-grid">

    <!-- Quantidade -->
    <div class="dosage-field">
        <input type="number"
               name="dose_quantity"
               class="dose-input"
               value="1"
               min="0.5"
               step="0.5"
               onchange="updatePreview()" />
        <span class="dose-unit">{{ unit_name }}</span>
    </div>

    <!-- Frequência -->
    <div class="dosage-field">
        <span class="dose-label">de</span>
        <select name="frequency" class="dose-select" onchange="updatePreview()">
            <option value="4">4/4h</option>
            <option value="6" selected>6/6h</option>
            <option value="8">8/8h</option>
            <option value="12">12/12h</option>
            <option value="24">1x/dia</option>
        </select>
    </div>

    <!-- Duração -->
    <div class="dosage-field">
        <span class="dose-label">por</span>
        <input type="number"
               name="duration"
               class="dose-input"
               value="7"
               min="1"
               onchange="updatePreview()" />
        <select name="duration_unit" class="dose-select" onchange="updatePreview()">
            <option value="dias" selected>dias</option>
            <option value="semanas">semanas</option>
            <option value="meses">meses</option>
        </select>
    </div>

    <!-- Opções especiais -->
    <div class="dosage-options">
        <label class="checkbox-label">
            <input type="checkbox" name="prn" onchange="updatePreview()" />
            Se necessário (SOS)
        </label>
        <label class="checkbox-label">
            <input type="checkbox" name="continuous" onchange="updatePreview()" />
            Uso contínuo
        </label>
    </div>

</div>
```

---

## CSS

```css
/* === PRESCRIPTION COMPOSER === */

.prescription-composer {
    @apply bg-white border border-soft-arctic rounded-lg p-4;
}

.composer-step {
    @apply mb-4 pb-4 border-b border-soft-arctic last:border-0;
}

.composer-step.hidden {
    @apply hidden;
}

.step-label {
    @apply block text-xs font-medium text-soft-steel mb-2
           uppercase tracking-wide;
}

/* === SEARCH === */

.search-container {
    @apply relative;
}

.search-input {
    @apply w-full px-4 py-3
           text-sm text-graphite-depth
           bg-white border border-soft-arctic rounded-lg
           focus:border-teal-intense focus:ring-2 focus:ring-teal-intense/20;
}

.search-results {
    @apply absolute top-full left-0 right-0 z-20
           mt-1 max-h-64 overflow-y-auto
           bg-white border border-soft-arctic rounded-lg shadow-lg;
}

.search-results:empty {
    @apply hidden;
}

.search-item {
    @apply px-4 py-3
           text-sm
           hover:bg-arctic-mist
           cursor-pointer
           border-b border-soft-arctic/50 last:border-0;
}

.search-item-name {
    @apply font-medium text-graphite-depth;
}

.search-item-substance {
    @apply text-xs text-soft-steel;
}

/* === OPTIONS GRID === */

.options-grid {
    @apply flex flex-wrap gap-2;
}

.option-drop {
    @apply px-4 py-2
           text-sm font-medium
           rounded-lg
           border
           cursor-pointer
           transition-all duration-200;
}

.option-drop:hover {
    @apply transform -translate-y-0.5 shadow-md;
}

.option-drop.selected {
    @apply ring-2 ring-offset-2 font-bold;
}

/* Cores por tipo */
.option-drop.drop-fofa {
    @apply bg-purple-50 text-purple-700 border-purple-200;
}

.option-drop.drop-fofa.selected {
    @apply ring-purple-500;
}

.option-drop.drop-strength {
    @apply bg-green-50 text-green-700 border-green-200;
}

.option-drop.drop-strength.selected {
    @apply ring-green-500;
}

.option-drop.drop-presentation {
    @apply bg-blue-50 text-blue-700 border-blue-200;
}

.option-drop.drop-presentation.selected {
    @apply ring-blue-500;
}

/* === DOSAGE COMPOSER === */

.dosage-grid {
    @apply space-y-3;
}

.dosage-field {
    @apply flex items-center gap-2;
}

.dose-input {
    @apply w-16 px-2 py-1
           text-center text-sm font-medium
           border border-soft-arctic rounded
           focus:border-teal-intense;
}

.dose-select {
    @apply px-2 py-1
           text-sm
           border border-soft-arctic rounded
           focus:border-teal-intense;
}

.dose-label {
    @apply text-sm text-soft-steel;
}

.dose-unit {
    @apply text-sm text-graphite-depth;
}

.dosage-options {
    @apply mt-3 pt-3 border-t border-soft-arctic
           flex flex-col gap-2;
}

.checkbox-label {
    @apply flex items-center gap-2
           text-sm text-graphite-depth
           cursor-pointer;
}

/* === PREVIEW === */

.composer-preview {
    @apply mt-4 pt-4 border-t border-soft-arctic;
}

.preview-label {
    @apply block text-xs font-medium text-soft-steel mb-2;
}

.preview-content {
    @apply px-4 py-3
           bg-mint-signal/20
           border border-mint-signal/30
           rounded-lg
           text-sm text-emerald-abyss
           font-medium
           whitespace-pre-line;
}
```

---

## JavaScript

```javascript
// Estado da composição
const rxState = {
    product: null,
    form: null,
    strength: null,
    presentation: null,
    dosage: {
        quantity: 1,
        frequency: 6,
        duration: 7,
        durationUnit: 'dias',
        prn: false,
        continuous: false
    }
};

// Selecionar opção e atualizar estado
function selectOption(element, step, value) {
    // Desmarcar outros da mesma categoria
    element.parentElement
        .querySelectorAll('.option-drop')
        .forEach(el => el.classList.remove('selected'));

    // Marcar selecionado
    element.classList.add('selected');

    // Atualizar estado
    rxState[step] = value;

    // Atualizar preview
    updatePreview();
}

// Atualizar preview da prescrição
function updatePreview() {
    const preview = document.querySelector('.preview-content');

    if (!rxState.product) {
        preview.textContent = 'Selecione um medicamento...';
        return;
    }

    let text = '';

    // Linha 1: Medicamento completo
    const parts = [rxState.product];
    if (rxState.strength) parts.push(rxState.strength);
    if (rxState.form) parts.push(rxState.form);
    text += parts.join(' ') + '\n';

    // Linha 2: Posologia
    if (rxState.dosage) {
        const d = rxState.dosage;
        text += `Tomar ${d.quantity} ${rxState.form || 'unidade'}(s) `;
        text += `de ${d.frequency}/${d.frequency} horas `;

        if (d.continuous) {
            text += 'uso contínuo';
        } else {
            text += `por ${d.duration} ${d.durationUnit}`;
        }

        if (d.prn) {
            text += ' se necessário';
        }
    }

    preview.textContent = text;
}

// Selecionar produto da busca
function selectProduct(productId, productName, substanceName) {
    rxState.product = productName;

    // Atualizar campo de busca
    document.querySelector('.search-input').value = productName;

    // Limpar resultados
    document.getElementById('search-results').innerHTML = '';

    // Carregar formas disponíveis
    htmx.ajax('GET', `/rx/forms/${productId}`, '#form-options');

    // Revelar próximo passo
    document.getElementById('step-form').classList.remove('hidden');

    updatePreview();
}
```

---

## Backend (Flask)

```python
from flask import Blueprint, render_template, request

rx = Blueprint('rx', __name__, url_prefix='/rx')

@rx.route('/search')
def search():
    """Buscar produtos por nome comercial ou substância"""
    query = request.args.get('query', '').strip()

    if len(query) < 2:
        return ''

    # Buscar no banco
    products = Product.search(query, limit=10)

    return render_template('rx/search_results.html', products=products)


@rx.route('/forms/<int:product_id>')
def forms(product_id):
    """Retornar formas farmacêuticas disponíveis para o produto"""
    forms = PharmaceuticalForm.get_by_product(product_id)

    return render_template('rx/form_options.html',
                          product_id=product_id,
                          forms=forms)


@rx.route('/strengths/<int:product_id>/<int:form_id>')
def strengths(product_id, form_id):
    """Retornar concentrações disponíveis para produto + forma"""
    strengths = Strength.get_by_product_form(product_id, form_id)

    return render_template('rx/strength_options.html',
                          product_id=product_id,
                          form_id=form_id,
                          strengths=strengths)


@rx.route('/presentations/<int:product_id>/<int:form_id>/<int:strength_id>')
def presentations(product_id, form_id, strength_id):
    """Retornar apresentações disponíveis"""
    presentations = Presentation.get_by_product_form_strength(
        product_id, form_id, strength_id
    )

    return render_template('rx/presentation_options.html',
                          presentations=presentations)


@rx.route('/dosage/<int:presentation_id>')
def dosage(presentation_id):
    """Retornar composer de posologia com unidade correta"""
    presentation = Presentation.get(presentation_id)

    return render_template('rx/dosage_composer.html',
                          unit_name=presentation.unit_name,
                          default_frequency=presentation.suggested_frequency)
```

---

## Variações

### Busca por substância (genérico)

Quando o usuário busca pela substância, mostrar produtos disponíveis:

```
┌─────────────────────────────────────┐
│ 🔍 "paracetamol"                    │
│                                     │
│ Resultados:                         │
│ ┌─────────────────────────────────┐ │
│ │ Tylenol (Paracetamol)           │ │
│ │ Johnson & Johnson               │ │
│ └─────────────────────────────────┘ │
│ ┌─────────────────────────────────┐ │
│ │ Paracetamol Genérico            │ │
│ │ EMS / Medley / Neo Química      │ │
│ └─────────────────────────────────┘ │
│ ┌─────────────────────────────────┐ │
│ │ Dorflex (Paracetamol + ...)     │ │
│ │ Sanofi                          │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────┘
```

### Atalho por concentração

Se o produto tem poucas formas, mostrar forma + concentração juntos:

```
┌─────────────────────────────────────┐
│ Tylenol (Paracetamol)               │
│                                     │
│ ┌──────────────┐ ┌──────────────┐   │
│ │ comprimido   │ │ comprimido   │   │
│ │ 500mg        │ │ 750mg        │   │
│ └──────────────┘ └──────────────┘   │
│                                     │
│ ┌──────────────┐ ┌──────────────┐   │
│ │ gotas        │ │ xarope       │   │
│ │ 200mg/mL     │ │ 32mg/mL      │   │
│ └──────────────┘ └──────────────┘   │
└─────────────────────────────────────┘
```

---

## Integração com Curadoria

Os dados para o Prescription Composer vêm da base curada:

- **VER_SUBSTANCES** → substâncias ativas
- **VER_PRODUCTS** → produtos comerciais
- **Pharmaceutical Forms** → formas farmacêuticas
- **Strengths** → concentrações
- **Presentations** → apresentações comerciais

A qualidade da curadoria impacta diretamente a experiência de prescrição.

---

*Última atualização: 2025-11-19*
*Versão: 1.0.0*
