1use chrono::{DateTime, Utc};
23use serde::{Deserialize, Serialize};
24
25use crate::bureau::RiskRating;
26use crate::credit::CreditTier;
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
34#[serde(rename_all = "snake_case")]
35pub enum InsuranceProductType {
36 TaskFailure,
38 FinancialError,
40 DataBreach,
42 SlaPenalty,
44}
45
46impl std::fmt::Display for InsuranceProductType {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 match self {
49 Self::TaskFailure => write!(f, "task_failure"),
50 Self::FinancialError => write!(f, "financial_error"),
51 Self::DataBreach => write!(f, "data_breach"),
52 Self::SlaPenalty => write!(f, "sla_penalty"),
53 }
54 }
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct InsuranceProduct {
60 pub product_id: String,
62 pub product_type: InsuranceProductType,
64 pub name: String,
66 pub description: String,
68 pub base_rate_bps: u32,
70 pub min_coverage_micro_usd: i64,
72 pub max_coverage_micro_usd: i64,
74 pub default_deductible_micro_usd: i64,
76 pub period_secs: u64,
78 pub min_trust_tier: InsuranceTrustTier,
80 pub provider_id: String,
82 pub active: bool,
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
88#[serde(rename_all = "snake_case")]
89pub enum InsuranceTrustTier {
90 Any,
92 Provisional,
94 Trusted,
96 Certified,
98}
99
100impl std::fmt::Display for InsuranceTrustTier {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 match self {
103 Self::Any => write!(f, "any"),
104 Self::Provisional => write!(f, "provisional"),
105 Self::Trusted => write!(f, "trusted"),
106 Self::Certified => write!(f, "certified"),
107 }
108 }
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct InsurancePolicy {
118 pub policy_id: String,
120 pub agent_id: String,
122 pub product_id: String,
124 pub product_type: InsuranceProductType,
126 pub coverage_limit_micro_usd: i64,
128 pub deductible_micro_usd: i64,
130 pub premium_micro_usd: i64,
132 pub status: PolicyStatus,
134 pub effective_from: DateTime<Utc>,
136 pub effective_until: DateTime<Utc>,
138 pub claims_paid_micro_usd: i64,
140 pub claims_count: u32,
142 pub provider_id: String,
144 pub issued_at: DateTime<Utc>,
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
150#[serde(rename_all = "snake_case")]
151pub enum PolicyStatus {
152 Active,
154 Expired,
156 Cancelled,
158 Suspended,
160 Exhausted,
162}
163
164impl std::fmt::Display for PolicyStatus {
165 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166 match self {
167 Self::Active => write!(f, "active"),
168 Self::Expired => write!(f, "expired"),
169 Self::Cancelled => write!(f, "cancelled"),
170 Self::Suspended => write!(f, "suspended"),
171 Self::Exhausted => write!(f, "exhausted"),
172 }
173 }
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct RiskAssessment {
183 pub agent_id: String,
185 pub risk_score: f64,
187 pub risk_rating: RiskRating,
189 pub credit_tier: CreditTier,
191 pub trust_score: f64,
193 pub components: RiskComponents,
195 pub premium_multiplier: f64,
197 pub insurable: bool,
199 #[serde(skip_serializing_if = "Option::is_none")]
201 pub denial_reason: Option<String>,
202 pub assessed_at: DateTime<Utc>,
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct RiskComponents {
209 pub operational_reliability: f64,
211 pub payment_reliability: f64,
213 pub economic_stability: f64,
215 pub task_completion_rate: f64,
217 pub account_maturity: f64,
219 pub claims_history: f64,
221}
222
223impl Default for RiskComponents {
224 fn default() -> Self {
225 Self {
226 operational_reliability: 0.5,
227 payment_reliability: 0.5,
228 economic_stability: 0.5,
229 task_completion_rate: 0.5,
230 account_maturity: 0.0,
231 claims_history: 1.0, }
233 }
234}
235
236#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct InsuranceClaim {
243 pub claim_id: String,
245 pub policy_id: String,
247 pub agent_id: String,
249 pub incident_type: InsuranceProductType,
251 pub claimed_amount_micro_usd: i64,
253 #[serde(skip_serializing_if = "Option::is_none")]
255 pub approved_amount_micro_usd: Option<i64>,
256 pub status: ClaimStatus,
258 pub description: String,
260 pub evidence_event_ids: Vec<String>,
262 #[serde(skip_serializing_if = "Option::is_none")]
264 pub session_id: Option<String>,
265 pub incident_at: DateTime<Utc>,
267 pub filed_at: DateTime<Utc>,
269 #[serde(skip_serializing_if = "Option::is_none")]
271 pub resolved_at: Option<DateTime<Utc>>,
272 #[serde(skip_serializing_if = "Option::is_none")]
274 pub resolution_notes: Option<String>,
275 #[serde(skip_serializing_if = "Option::is_none")]
277 pub verification: Option<ClaimVerification>,
278}
279
280#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
282#[serde(rename_all = "snake_case")]
283pub enum ClaimStatus {
284 Submitted,
286 Verifying,
288 Approved,
290 Denied,
292 Paid,
294 UnderReview,
296 Withdrawn,
298}
299
300impl std::fmt::Display for ClaimStatus {
301 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
302 match self {
303 Self::Submitted => write!(f, "submitted"),
304 Self::Verifying => write!(f, "verifying"),
305 Self::Approved => write!(f, "approved"),
306 Self::Denied => write!(f, "denied"),
307 Self::Paid => write!(f, "paid"),
308 Self::UnderReview => write!(f, "under_review"),
309 Self::Withdrawn => write!(f, "withdrawn"),
310 }
311 }
312}
313
314#[derive(Debug, Clone, Serialize, Deserialize)]
316pub struct ClaimVerification {
317 pub incident_confirmed: bool,
319 pub evidence_events_validated: u32,
321 pub evidence_events_total: u32,
323 pub amount_consistent: bool,
325 pub policy_active_at_incident: bool,
327 pub confidence: f64,
329 pub notes: Vec<String>,
331 pub verified_at: DateTime<Utc>,
333}
334
335#[derive(Debug, Clone, Serialize, Deserialize)]
341pub struct InsurancePool {
342 pub pool_id: String,
344 pub name: String,
346 pub reserves_micro_usd: i64,
348 pub total_contributions_micro_usd: i64,
350 pub total_payouts_micro_usd: i64,
352 pub active_policies: u32,
354 pub total_coverage_outstanding_micro_usd: i64,
356 pub reserve_ratio: f64,
358 pub management_fee_bps: u32,
360 pub min_reserve_ratio: f64,
362 pub status: PoolStatus,
364 pub created_at: DateTime<Utc>,
366}
367
368#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
370#[serde(rename_all = "snake_case")]
371pub enum PoolStatus {
372 Active,
374 Paused,
376 WindingDown,
378}
379
380impl std::fmt::Display for PoolStatus {
381 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
382 match self {
383 Self::Active => write!(f, "active"),
384 Self::Paused => write!(f, "paused"),
385 Self::WindingDown => write!(f, "winding_down"),
386 }
387 }
388}
389
390#[derive(Debug, Clone, Serialize, Deserialize)]
396pub struct InsuranceProvider {
397 pub provider_id: String,
399 pub name: String,
401 pub provider_type: ProviderType,
403 pub offered_products: Vec<InsuranceProductType>,
405 pub commission_rate_bps: u32,
407 pub active: bool,
409 #[serde(skip_serializing_if = "Option::is_none")]
411 pub api_endpoint: Option<String>,
412 pub registered_at: DateTime<Utc>,
414}
415
416#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
418#[serde(rename_all = "snake_case")]
419pub enum ProviderType {
420 SelfInsurancePool,
422 LicensedInsurer,
424 Parametric,
426}
427
428impl std::fmt::Display for ProviderType {
429 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
430 match self {
431 Self::SelfInsurancePool => write!(f, "self_insurance_pool"),
432 Self::LicensedInsurer => write!(f, "licensed_insurer"),
433 Self::Parametric => write!(f, "parametric"),
434 }
435 }
436}
437
438#[derive(Debug, Clone, Serialize, Deserialize)]
440pub struct InsuranceQuote {
441 pub quote_id: String,
443 pub agent_id: String,
445 pub product_id: String,
447 pub product_type: InsuranceProductType,
449 pub coverage_micro_usd: i64,
451 pub deductible_micro_usd: i64,
453 pub premium_micro_usd: i64,
455 pub period_secs: u64,
457 pub risk_assessment: RiskAssessment,
459 pub provider_id: String,
461 pub valid_until: DateTime<Utc>,
463 pub quoted_at: DateTime<Utc>,
465}
466
467#[derive(Debug, Clone, Serialize, Deserialize)]
473pub struct QuoteRequest {
474 pub agent_id: String,
476 pub product_type: InsuranceProductType,
478 pub coverage_micro_usd: i64,
480 #[serde(skip_serializing_if = "Option::is_none")]
482 pub preferred_provider_id: Option<String>,
483}
484
485#[derive(Debug, Clone, Serialize, Deserialize)]
487pub struct BindRequest {
488 pub quote_id: String,
490 pub agent_id: String,
492}
493
494#[derive(Debug, Clone, Serialize, Deserialize)]
496pub struct ClaimRequest {
497 pub policy_id: String,
499 pub agent_id: String,
501 pub incident_type: InsuranceProductType,
503 pub claimed_amount_micro_usd: i64,
505 pub description: String,
507 pub evidence_event_ids: Vec<String>,
509 #[serde(skip_serializing_if = "Option::is_none")]
511 pub session_id: Option<String>,
512 pub incident_at: DateTime<Utc>,
514}
515
516#[derive(Debug, Clone, Serialize, Deserialize)]
518pub struct PoolContributionRequest {
519 pub agent_id: String,
521 pub amount_micro_usd: i64,
523}
524
525#[cfg(test)]
526mod tests {
527 use super::*;
528
529 #[test]
530 fn product_type_serde_roundtrip() {
531 let pt = InsuranceProductType::TaskFailure;
532 let json = serde_json::to_string(&pt).unwrap();
533 assert_eq!(json, "\"task_failure\"");
534 let back: InsuranceProductType = serde_json::from_str(&json).unwrap();
535 assert_eq!(back, pt);
536 }
537
538 #[test]
539 fn policy_status_display() {
540 assert_eq!(PolicyStatus::Active.to_string(), "active");
541 assert_eq!(PolicyStatus::Suspended.to_string(), "suspended");
542 }
543
544 #[test]
545 fn claim_status_display() {
546 assert_eq!(ClaimStatus::Submitted.to_string(), "submitted");
547 assert_eq!(ClaimStatus::Paid.to_string(), "paid");
548 assert_eq!(ClaimStatus::UnderReview.to_string(), "under_review");
549 }
550
551 #[test]
552 fn provider_type_serde_roundtrip() {
553 let pt = ProviderType::SelfInsurancePool;
554 let json = serde_json::to_string(&pt).unwrap();
555 assert_eq!(json, "\"self_insurance_pool\"");
556 let back: ProviderType = serde_json::from_str(&json).unwrap();
557 assert_eq!(back, pt);
558 }
559
560 #[test]
561 fn risk_components_default() {
562 let rc = RiskComponents::default();
563 assert_eq!(rc.claims_history, 1.0);
564 assert_eq!(rc.account_maturity, 0.0);
565 }
566
567 #[test]
568 fn insurance_trust_tier_ordering() {
569 assert!(InsuranceTrustTier::Any < InsuranceTrustTier::Provisional);
570 assert!(InsuranceTrustTier::Provisional < InsuranceTrustTier::Trusted);
571 assert!(InsuranceTrustTier::Trusted < InsuranceTrustTier::Certified);
572 }
573
574 #[test]
575 fn pool_status_display() {
576 assert_eq!(PoolStatus::Active.to_string(), "active");
577 assert_eq!(PoolStatus::WindingDown.to_string(), "winding_down");
578 }
579}