# Core Operations

Operaţii principale care orchestrează aplicaţia.

## AppData Lifecycle

`AppData` este singleton-ul global care orchestrează toate subsistemele.

### Inițializare

```swift
let appData = AppData()
```

- **MUST**: Se instanțiază în `AppDelegate.application(_:didFinishLaunchingWithOptions:)`
- **MUST**: Se accesează din `SceneDelegate.scene(_:willConnectTo:options:)`
- **MUST**: Inițializează `NSPersistentCloudKitContainer` cu name `"CKModel"`
- **MUST**: Inițializează `CloudDeviceSettingsStore` (wraps NSManagedObjectContext)

### Startup sequence

1. `AppDelegate.application(_:didFinishLaunchingWithOptions:)`:
   - Crează `AppData()`
   - Inițializează Core Data stack
   - Încarcă migrări din `cloudStoreRebuildVersion`

2. `SceneDelegate.scene(_:willConnectTo:options:)`:
   - Apelează `appData.activateCloudDeviceSync(context: sceneContext)`
   - Inițiază BT scanning
   - Inițiază CloudKit sync

### Shutdown sequence

- **SHOULD**: Finalizează sesiuni active la app terminate
- **MUST**: Salvează Core Data context (`saveIfNeeded()`)
- **SHOULD**: Deconectează BT graceful

## Bluetooth Connection Management

### Connection state machine

```
notPresent
  ↓
peripheralNotConnected ← (user disconnect)
  ↓
peripheralConnectionPending
  ↓
peripheralConnected
  ↓
peripheralReady
  ↓
comunicating ↔ dataIsAvailable
```

### Operations

```swift
// Conectare inițială
blutooth.connect(to peripheralUUID: UUID, type: Model)
// MUST: inițiază CBCentralManager scan
// MUST: se conectează la UUID specific
// SHOULD: timeout = 5s
// MUST: pe succes, tranzițe la peripheralConnected

// Deconectare
bluetooth.disconnect(from meter: Meter)
// MUST: anulează reconnect logic
// MUST: eliberează resurse
// MUST: marchez ca manual disconnect

// Auto-reconnect
bluetooth.autoReconnect(meter: Meter, backoff: Backoff)
// SHOULD: exponential backoff: 1s, 2s, 4s, 8s, max 60s
// MUST: anulează dacă utilizator disconnect manual
// MUST: max 3 retry-uri consecutive
```

## Measurement Recording

### Session lifecycle

```swift
let session = meter.startChargeRecord(for: device)
```

1. **Start**: Crează `ChargeRecord(sessionID: UUID(), startTime: now())`
2. **Measure**: La fiecare 1-2s:
   ```swift
   let measurement = meter.lastDataPoint
   session.addMeasurement(measurement)
   ```
3. **End**: 
   ```swift
   meter.endChargeRecord(session)
   ```
   - Calculează `totalEnergy = ∑(V * A * Δt)`
   - Marchez ca `completed`
   - Salvează în Core Data

### Invarianţi

- **MUST**: O sesiune activă per meter
- **MUST**: Măsurătorile sunt cronologice
- **MUST**: `startTime <= now() <= (endTime || ∞)`
- **MUST**: Energia ≥ 0

### Recording frequency

- **SHOULD**: Măsurători la ~1Hz (1000ms interval)
- **MAY**: Reduce frequency dacă battery low
- **SHOULD**: Drop măsurători dacă queue > 100 items

## Cloud Sync

### Main concepts

- **DeviceSettings**: entitate Core Data persistă MAC, name, temperature unit
- **CloudDeviceSettingsStore**: wrapper pe NSManagedObjectContext
- **Rebuild version**: `cloudStoreRebuildVersion` (curent: 3)

### Sync flow

1. **Upload**: Locale changes → Core Data → CloudKit
   ```swift
   cloudStore.upsertDeviceSettings(
       macAddress: "AA:BB:CC:DD:EE:FF",
       meterName: "Kitchen Meter",
       tc66TemperatureUnit: .celsius,
       connectionMetadata: ...
   )
   ```
   - MUST: salvează în Core Data sync
   - MUST: CloudKit container replica-ază automat

2. **Download**: CloudKit changes → Core Data → UI
   - **MUST**: NSPersistentCloudKitContainer sincronizează automat
   - **SHOULD**: Refresh UI după fetch

3. **Conflict resolution**: Dacă două modificări simultane
   - **MUST**: Mergi pe "last write wins" dacă timestamps diferă
   - **SHOULD**: Loghează conflictul pentru debugging

### Discovery throttling

- **MUST**: Max 1 discovery per device per 120s
- **SHOULD**: Previne CloudKit thrashing din repeat BT advertisements
- **MUST**: Reseta timer dacă device disconnect-ează

## Device Settings Persistence

### MAC address mapping

```swift
// CloudDeviceSettingsStore.swift
func upsertDeviceSettings(
    macAddress: String,
    meterName: String,
    tc66TemperatureUnit: TemperatureUnitPreference?,
    connectionMetadata: ConnectionMetadata?,
    discoveryMetadata: DiscoveryMetadata?
)
```

- **MUST**: macAddress optional (datorită migration)
- **MUST**: meterName unic pe meter (no duplicates)
- **SHOULD**: connectionMetadata.expiresAt = now() + 24h

### Legacy KV Store

`NSUbiquitousKeyValueStore` sincronizează:
- `MeterNames`: {macAddress → meterName}
- `TC66TemperatureUnits`: {macAddress → unit}

- **MUST**: Menţinere backward compat
- **SHOULD**: Migrate pe Core Data la first sync
- **MAY**: Drop la următoarea major version

## Error handling

### Bluetooth errors

```
Error: BT peripheral not found
→ Retry connect cu backoff
→ Max 3 retries, apoi fallback offline mode

Error: Characteristic not found
→ Log error
→ Mark meter incompatible (UI warning)

Error: Read timeout
→ Retry measurement request
→ Increment timeout counter
```

### CloudKit errors

```
Error: Network unavailable
→ Queue pending changes
→ Retry la next network change

Error: Conflict detected
→ Merge data (last write wins)
→ Retry sync

Error: Quota exceeded
→ Log error
→ Notify user (prune old data?)
```

## Testare

### Unit tests

```swift
test_appDataInitializes_CoreDataAndCloudKit()
test_bluetoothConnectInitiatesProperStateTransition()
test_bluetoothDisconnect_CleansUp()
test_autoReconnectBackoff_ExponentialScaling()
test_sessionStartCreatesValidRecord()
test_sessionEndCalculatesEnergy()
test_cloudSyncUpsert_SavesToCoreData()
test_discoveryThrottling_RespectsTiming()
test_conflictResolution_LastWriteWins()
```

### Integration tests

- [ ] Full app startup (BT + CloudKit)
- [ ] Connect meter → start session → record measurements → end session
- [ ] Disconnect meter → reconnect avec backoff
- [ ] Device settings sync CloudKit → other device
- [ ] Offline mode (queue changes, sync later)

## Dependenţe

- `AppData`: orchestrează tot
- `BluetoothManager`: gestionează Core Bluetooth
- `CloudDeviceSettingsStore`: Core Data + CloudKit
- `ChargeInsightsStore`: sesiuni persistente
- `ConsumptionMonitorStore`: monitorizare consum

## Notes

- Legat: [CloudKit Sync](./CloudKitSync.md)
- Legat: [Bluetooth Discovery](./BluetoothDiscovery.md)
- Referință: AppDelegate.swift, SceneDelegate.swift
