use tici_common::{cdc_file_name::CDCFileName, index::IndexKey};
use tici_grpc::ShardManifestHeader;

pub mod compactor;
pub mod config;
pub mod reader;
pub mod writer;

pub mod analysis;
pub mod data_types;
pub mod metadata;
pub mod utils;

pub mod test_utils;

use anyhow::Result;
use serde::{Deserialize, Serialize};

use crate::utils::key::ShardingKeyRange;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(transparent)]
pub struct ShardWriterMetaVersion(u32);

impl ShardWriterMetaVersion {
    pub const V0: Self = Self(0);

    pub const LATEST: Self = Self::V0;
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CDCCheckpoint {
    pub bucket: String,
    pub table_prefix: String,
    pub last_file: CDCFileName,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FragLocation {
    pub bucket: String,
    pub prefix: String,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ShardWriterMeta {
    pub version: ShardWriterMetaVersion,
    pub index_key: IndexKey,
    pub shard_header: ShardManifestHeader,
    pub frag_location: FragLocation,
    pub cdc_checkpoint: CDCCheckpoint,
}

impl ShardWriterMeta {
    pub fn keyspace_id(&self) -> u32 {
        self.index_key.keyspace_id
    }

    pub fn table_id(&self) -> i64 {
        self.index_key.table_id
    }

    pub fn index_id(&self) -> i64 {
        self.index_key.index_id
    }

    pub fn shard_sub_path(&self) -> String {
        tici_common::s3_keys::shard_key(
            self.keyspace_id(),
            self.table_id(),
            self.index_id(),
            self.shard_header.shard_id,
        )
    }

    pub fn shard_tracing_id(&self) -> String {
        utils::shard_tracing_id(&self.index_key, self.shard_header.shard_id)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(transparent)]
pub struct ShardMirrorMetaVersion(u32);

impl ShardMirrorMetaVersion {
    pub const V0: Self = Self(0);

    pub const LATEST: Self = Self::V0;
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ShardMirrorMeta {
    pub version: ShardMirrorMetaVersion,
    pub index_key: IndexKey,
    pub shard_header: ShardManifestHeader,
    pub frag_bucket: String,
}

impl ShardMirrorMeta {
    pub fn shard_tracing_id(&self) -> String {
        utils::shard_tracing_id(&self.index_key, self.shard_header.shard_id)
    }

    pub fn shard_range(&self) -> Result<ShardingKeyRange> {
        ShardingKeyRange::half_open(
            self.shard_header.start_key.clone(),
            self.shard_header.end_key.clone(),
        )
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(transparent)]
pub struct FragMetaVersion(u32);

impl FragMetaVersion {
    pub const V0: Self = Self(0);

    pub const LATEST: Self = Self::V0;
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FragMetaWrapper {
    pub version: FragMetaVersion,
    pub seq: u64, // sequence number of the frag metas
    pub frag_metas: Vec<tici_grpc::FragMeta>,
}
