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 EventSnapshot {
    pub id: Uuid,
    pub sport_type: String,
    pub source_ref: String,
    pub title_en: String,
    pub title_sv: String,
    pub status: String,
    pub preview_start_ms: i64,
    pub preview_end_ms: i64,
    pub reveal_start_ms: i64,
    pub reveal_end_ms: i64,
    pub lock_at: DateTime<Utc>,
    pub settle_at: DateTime<Utc>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct EventMediaSnapshot {
    pub id: Uuid,
    pub event_id: Uuid,
    pub media_type: String,
    pub hls_master_url: String,
    pub poster_url: Option<String>,
    pub duration_ms: i64,
    pub preview_start_ms: i64,
    pub preview_end_ms: i64,
    pub reveal_start_ms: i64,
    pub reveal_end_ms: i64,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct OutcomeSnapshot {
    pub id: Uuid,
    pub market_id: Uuid,
    pub outcome_code: String,
    pub label_key: String,
    pub sort_order: i32,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MarketSnapshot {
    pub id: Uuid,
    pub event_id: Uuid,
    pub question_key: String,
    pub market_type: String,
    pub status: String,
    pub lock_at: DateTime<Utc>,
    pub settlement_rule_key: String,
    pub outcomes: Vec<OutcomeSnapshot>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct EventManifestSnapshot {
    pub event: EventSnapshot,
    pub media: Vec<EventMediaSnapshot>,
    pub markets: Vec<MarketSnapshot>,
}

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

#[derive(Default)]
struct EventsState {
    feed_order: Vec<Uuid>,
    manifests_by_event_id: HashMap<Uuid, EventManifestSnapshot>,
}

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

    pub fn from_fixture(fixture: &SampleStudyFixture) -> Self {
        let mut manifests_by_event_id = HashMap::new();
        manifests_by_event_id.insert(fixture.manifest.event.id, fixture.manifest.clone());

        Self {
            inner: Arc::new(RwLock::new(EventsState {
                feed_order: vec![fixture.manifest.event.id],
                manifests_by_event_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 preview_start = 0;
        let preview_end = 45_000;
        let reveal_start = 50_000;
        let reveal_end = 90_000;
        let lock_at = Utc::now() + ChronoDuration::minutes(10);
        let settle_at = Utc::now() + ChronoDuration::minutes(25);

        let event = EventSnapshot {
            id: event_id,
            sport_type: "football".to_string(),
            source_ref: "sample-event-001".to_string(),
            title_en: "Late winner chance".to_string(),
            title_sv: "Möjlighet till segermål".to_string(),
            status: "prefetch_ready".to_string(),
            preview_start_ms: preview_start,
            preview_end_ms: preview_end,
            reveal_start_ms: reveal_start,
            reveal_end_ms: reveal_end,
            lock_at,
            settle_at,
        };

        let media = EventMediaSnapshot {
            id: Uuid::parse_str("33333333-3333-3333-3333-333333333333").expect("valid uuid"),
            event_id,
            media_type: "hls_main".to_string(),
            hls_master_url: "https://cdn.example.com/hermes/sample-event/master.m3u8".to_string(),
            poster_url: Some("https://cdn.example.com/hermes/sample-event/poster.jpg".to_string()),
            duration_ms: 90_000,
            preview_start_ms: preview_start,
            preview_end_ms: preview_end,
            reveal_start_ms: reveal_start,
            reveal_end_ms: reveal_end,
        };

        let market = MarketSnapshot {
            id: market_id,
            event_id,
            question_key: "market.sample.winner".to_string(),
            market_type: "winner".to_string(),
            status: "open".to_string(),
            lock_at,
            settlement_rule_key: "settle_on_match_winner".to_string(),
            outcomes: vec![
                OutcomeSnapshot {
                    id: Uuid::parse_str("44444444-4444-4444-4444-444444444444").expect("valid uuid"),
                    market_id,
                    outcome_code: "home".to_string(),
                    label_key: "outcome.home".to_string(),
                    sort_order: 1,
                },
                OutcomeSnapshot {
                    id: Uuid::parse_str("55555555-5555-5555-5555-555555555555").expect("valid uuid"),
                    market_id,
                    outcome_code: "away".to_string(),
                    label_key: "outcome.away".to_string(),
                    sort_order: 2,
                },
            ],
        };

        let manifest = EventManifestSnapshot {
            event,
            media: vec![media],
            markets: vec![market],
        };

        let mut manifests_by_event_id = HashMap::new();
        manifests_by_event_id.insert(event_id, manifest);

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

    pub async fn insert_manifest(&self, manifest: EventManifestSnapshot) -> EventManifestSnapshot {
        let mut state = self.inner.write().await;
        let event_id = manifest.event.id;
        if !state.manifests_by_event_id.contains_key(&event_id) {
            state.feed_order.push(event_id);
        }
        state.manifests_by_event_id.insert(event_id, manifest.clone());
        manifest
    }

    pub async fn insert_market(&self, event_id: Uuid, market: MarketSnapshot) -> bool {
        let mut state = self.inner.write().await;
        let Some(manifest) = state.manifests_by_event_id.get_mut(&event_id) else {
            return false;
        };

        let Some(existing) = manifest.markets.iter_mut().find(|existing| existing.id == market.id) else {
            manifest.markets.push(market);
            return true;
        };

        *existing = market;
        true
    }

    pub async fn next_event(&self) -> Option<EventSnapshot> {
        let state = self.inner.read().await;
        let Some(event_id) = state.feed_order.first() else {
            return None;
        };
        let Some(manifest) = state.manifests_by_event_id.get(event_id) else {
            return None;
        };
        Some(manifest.event.clone())
    }

    pub async fn get_event(&self, event_id: Uuid) -> Option<EventSnapshot> {
        let state = self.inner.read().await;
        let Some(manifest) = state.manifests_by_event_id.get(&event_id) else {
            return None;
        };
        Some(manifest.event.clone())
    }

    pub async fn get_manifest(&self, event_id: Uuid) -> Option<EventManifestSnapshot> {
        let state = self.inner.read().await;
        let Some(manifest) = state.manifests_by_event_id.get(&event_id) else {
            return None;
        };
        Some(manifest.clone())
    }
}
