# Powerbank Entity

Reprezentarea unei baterii externe (sursă de energie portabilă).

## Responsabilități

- Modelarea unei surse portabile de putere
- Gestionarea sesiunilor de descărcare
- Urmărirea stării de încărcare
- Detectarea şi merge-ul duplicate-ilor

## Invarianţi

- **MUST**: Fiecare Powerbank are un `id` (UUID) unic
- **MUST**: Capacity (mAh) trebuie să fie pozitiv
- **MUST**: Un Powerbank poate avea multiple sesiuni de descărcare (neordonate pe timp)
- **MUST**: Sesiunile sunt asociate unui Meter specific
- **SHOULD**: Powerbank-ul cu 0 sesiuni ar trebui marcat pentru curatare
- **MUST**: Nu pot exista duplicate fizice pe același MAC address fără merge explicare

## Categoriile

Un Powerbank este o subcategorie a `ChargedDevice` cu `class = .powerbank`.

## API Public

### Proprietăţi

| Proprietate | Tip | Descriere | Observaţii |
|---|---|---|---|
| `id` | UUID | Identificator unic | Generat la criere |
| `name` | String | Nume (ex: "Anker 10000mAh") | Ales de utilizator |
| `macAddress` | String | Adresa BT | Pentru identificare unică |
| `capacity` | Int | Capacitate în mAh | Trebuie să fie > 0 |
| `dischargeSessions` | [DischargeSession] | Sesiunile de descărcare | Cronologice |
| `totalEnergyDelivered` | Double | Total Wh furnizat | Calculat din sesiuni |
| `createdAt` | Date | Data creării | Immutable |
| `lastDischargedAt` | Date? | Data ultimei sesiuni | Nullable |

### Metode

```swift
// Gestionare sesiuni
func startDischargeSession(meter: Meter) -> DischargeSession
// MUST: sessionID = UUID()
// MUST: startTime = now()
// MUST: retur DischargeSession cu status "active"
// SHOULD: capacity nu scade (immutable)

func recordDischargePoint(_ measurement: Measurement, in session: DischargeSession)
// Înregistrează o măsurătoare de descărcare
// MUST: measurement.timestamp > session.startTime
// MUST: nu merge dacă sesiunea e completată

func endDischargeSession(_ session: DischargeSession)
// MUST: endTime = now()
// MUST: calculează energie furnizată = ∑(V * A * Δt)
// MUST: marchez sesiunea ca "completed"

func recalculateTotalEnergy()
// Recalculează totalul de Wh furnizat
// SHOULD: se apelează după merge

// Duplicate handling
func mergeWith(_ other: Powerbank)
// MUST: combină toate sesiunile din ambele PB-uri
// MUST: elimină duplicate-urile de sesiuni
// MUST: recalculează totalul
// SHOULD: logs operaţia
// MUST: marchez celalalt Powerbank ca "merged"

// Naming
func rename(to newName: String)
// MUST: actualizează name property
// MUST: persistă în Core Data
```

## Comportamente critice

### Sesiuni de descărcare

- **MUST**: Doar o sesiune activă per Powerbank la orice moment
- **MUST**: Sesiunile completate nu pot fi modificate
- **SHOULD**: Sesiunile care durează > 48h sunt marcate cu warning (posibil inactive)
- **MAY**: Sesiuni orfane (meter deconectat > 2h) pot fi finalizate automat

### Calculul energiei

- **MUST**: Energie furnizată = ∑(V_out * A_out * Δt) pentru intervale
- **MUST**: Unitatea = Wh (Watt-hours)
- **MUST**: Trebuie să fie ne-negativă (energia nu poate fi absorbi-u înapoi)
- **SHOULD**: Loghează warning dacă energia e negativă (date inconsistente)

### Duplicate detection și merge

Se declanşează când:
1. Două Powerbanks cu același MAC address
2. Două Powerbanks cu sesiuni suprapuse pe aceeași perioadă

Rezoluţie:
- **MUST**: Sesiunea cu mai multe măsurători = "winner"
- **MUST**: Energiile sunt adunate (∑)
- **MUST**: Sesiunile sunt deduplicate după sessionID
- **SHOULD**: Old Powerbank e marcat ca "merged"
- **MAY**: Notifică utilizator

### State after merge

- **MUST**: După merge, alte referințe la old Powerbank trebuie actualizate
- **MUST**: Sessionuri din old PB redirecţionează la new PB
- **SHOULD**: Old PB e marcat ReadOnly sau Hidden

## Testare

### Unit tests

```swift
// Sesiuni
test_startSessionCreatesValidRecord()
test_endSessionCalculatesEnergy()
test_activeSessions_OnlyOne()

// Măsurători
test_recordPointFailsIfSessionEnded()
test_measurementOrdering()

// Merge
test_mergeDetectsDuplicates()
test_mergeKeepsMoreCompleteData()
test_mergeRecalculatesTotalEnergy()
test_mergeMarksOldAsMerged()

// Naming
test_renameUpdatesPersistence()

// Validare
test_capacityMustBePositive()
test_energyCannotBeNegative()
```

### Integration tests

- [ ] Powerbank apare după start sesiune
- [ ] Sesiuni complete salvate în Core Data
- [ ] CloudKit sync merge-ul corect
- [ ] Energiile sunt consistente post-merge
- [ ] Name changes persistent pe CloudKit
- [ ] Capacity e immutable (nu se schimbă)

## Dependenţe

- `Meter`: pentru măsurători
- `ChargeInsightsStore`: persistență sesiuni
- `CloudKitSync`: replicare iCloud
- `ChargedDevice`: Powerbank e subcategorie

## Notes

Documentaţie asoc:
- [Powerbank Category](../Powerbank%20Category.md)
- [Charge Session Integrity](../Charge%20Session%20Integrity%20and%20Conflict%20Healing.md)
- **Status**: Adăugat recent (commit: 0772cad)
- **Merge class+template**: plan în progress, schema v20
