use std::{collections::HashMap, sync::Arc};

use chrono::{DateTime, Duration as ChronoDuration, Utc};
use serde::{Deserialize, Serialize};
use tokio::sync::RwLock;
use uuid::Uuid;

use crate::fixtures::SampleStudyFixture;

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SettlementSnapshot {
    pub id: Uuid,
    pub market_id: Uuid,
    pub settled_at: DateTime<Utc>,
    pub winning_outcome_id: Uuid,
}

#[derive(Clone, Default)]
pub struct SettlementsStore {
    inner: Arc<RwLock<SettlementsState>>,
}

#[derive(Default)]
struct SettlementsState {
    settlements_by_event_id: HashMap<Uuid, SettlementSnapshot>,
    settlements_by_market_id: HashMap<Uuid, SettlementSnapshot>,
}

impl SettlementsStore {
    pub fn new() -> Self {
        Self::from_fixture(&crate::fixtures::load_sample_study_fixture())
    }

    pub fn from_fixture(fixture: &SampleStudyFixture) -> Self {
        let mut settlements_by_event_id = HashMap::new();
        settlements_by_event_id.insert(fixture.settlement.event_id, fixture.settlement.settlement.clone());

        let mut settlements_by_market_id = HashMap::new();
        settlements_by_market_id.insert(
            fixture.settlement.settlement.market_id,
            fixture.settlement.settlement.clone(),
        );

        Self {
            inner: Arc::new(RwLock::new(SettlementsState {
                settlements_by_event_id,
                settlements_by_market_id,
            })),
        }
    }

    #[allow(dead_code, unused_variables)]
    pub fn with_sample_data() -> Self {
        let event_id = Uuid::parse_str("11111111-1111-1111-1111-111111111111").expect("valid uuid");
        let market_id = Uuid::parse_str("22222222-2222-2222-2222-222222222222").expect("valid uuid");
        let winning_outcome_id = Uuid::parse_str("44444444-4444-4444-4444-444444444444").expect("valid uuid");

        let settlement = SettlementSnapshot {
            id: Uuid::parse_str("99999999-9999-9999-9999-999999999999").expect("valid uuid"),
            market_id,
            settled_at: Utc::now() - ChronoDuration::minutes(5),
            winning_outcome_id,
        };

        let mut settlements_by_event_id = HashMap::new();
        settlements_by_event_id.insert(event_id, settlement.clone());

        let mut settlements_by_market_id = HashMap::new();
        settlements_by_market_id.insert(market_id, settlement.clone());

        Self::from_fixture(&crate::fixtures::load_sample_study_fixture())
    }

    pub async fn settlement_for_event(&self, event_id: Uuid) -> Option<SettlementSnapshot> {
        let state = self.inner.read().await;
        let Some(settlement) = state.settlements_by_event_id.get(&event_id) else {
            return None;
        };
        Some(settlement.clone())
    }

    pub async fn settlement_for_market(&self, market_id: Uuid) -> Option<SettlementSnapshot> {
        let state = self.inner.read().await;
        let Some(settlement) = state.settlements_by_market_id.get(&market_id) else {
            return None;
        };
        Some(settlement.clone())
    }

    pub async fn upsert(&self, event_id: Uuid, settlement: SettlementSnapshot) -> SettlementSnapshot {
        let mut state = self.inner.write().await;
        state.settlements_by_event_id.insert(event_id, settlement.clone());
        state
            .settlements_by_market_id
            .insert(settlement.market_id, settlement.clone());
        settlement
    }
}
