use anyhow::bail;
use serde::{Deserialize, Serialize};
use tokio_postgres::Row;

#[derive(Serialize, Deserialize, Debug)]
pub struct Type {
    pub id: TypeId,
    pub name: String,
}

impl TryFrom<&Row> for Type {
    type Error = crate::Error;

    fn try_from(value: &Row) -> Result<Self, Self::Error> {
        let id: i64 = value.try_get("id")?;
        let name: String = value.try_get("name")?;

        Ok(Type {
            id: id.try_into()?,
            name: name,
        })
    }
}

impl TryFrom<i64> for TypeId {
    type Error = anyhow::Error;

    fn try_from(value: i64) -> Result<Self, Self::Error> {
        let id = match value {
            1 => TypeId::PRIVATE,
            2 => TypeId::Misc,
            3 => TypeId::Right,
            4 => TypeId::Preference,
            5 => TypeId::MLP,
            6 => TypeId::RoyaltyTrst,
            7 => TypeId::CDI,
            8 => TypeId::TrackingStk,
            9 => TypeId::DutchCert,
            10 => TypeId::CommonStock,
            11 => TypeId::NVDR,
            12 => TypeId::OpenEndFund,
            13 => TypeId::Unit,
            14 => TypeId::SavingsShare,
            15 => TypeId::GDR,
            16 => TypeId::REIT,
            17 => TypeId::StapledSecurity,
            18 => TypeId::ClosedEndFund,
            19 => TypeId::SDR,
            20 => TypeId::ForeignSh,
            21 => TypeId::NYRegShrs,
            22 => TypeId::ETP,
            23 => TypeId::PUBLIC,
            24 => TypeId::LtdPart,
            25 => TypeId::EquityWRT,
            26 => TypeId::ADR,
            27 => TypeId::Receipt,
            28 => TypeId::None,
            _ => bail!("couldn't match value {value} to TypeId"),
        };
        Ok(id)
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub enum TypeId {
    PRIVATE = 1,
    Misc = 2,
    Right = 3,
    Preference = 4,
    MLP = 5,
    RoyaltyTrst = 6,
    CDI = 7,
    TrackingStk = 8,
    DutchCert = 9,
    CommonStock = 10,
    NVDR = 11,
    OpenEndFund = 12,
    Unit = 13,
    SavingsShare = 14,
    GDR = 15,
    REIT = 16,
    StapledSecurity = 17,
    ClosedEndFund = 18,
    SDR = 19,
    ForeignSh = 20,
    NYRegShrs = 21,
    ETP = 22,
    PUBLIC = 23,
    LtdPart = 24,
    EquityWRT = 25,
    ADR = 26,
    Receipt = 27,
    None = 28,
}

impl TypeId {
    pub fn get_name_from_id(&self) -> String {
        let v = match self {
            TypeId::PRIVATE => "PRIVATE",
            TypeId::Misc => "Misc.",
            TypeId::Right => "Right",
            TypeId::Preference => "Preference",
            TypeId::MLP => "MLP",
            TypeId::RoyaltyTrst => "Royalty Trst",
            TypeId::CDI => "CDI",
            TypeId::TrackingStk => "Tracking Stk",
            TypeId::DutchCert => "Dutch Cert",
            TypeId::CommonStock => "Common Stock",
            TypeId::NVDR => "NVDR",
            TypeId::OpenEndFund => "Open-End Fund",
            TypeId::Unit => "Unit",
            TypeId::SavingsShare => "Savings Share",
            TypeId::GDR => "GDR",
            TypeId::REIT => "REIT",
            TypeId::StapledSecurity => "Stapled Security",
            TypeId::ClosedEndFund => "Closed-End Fund",
            TypeId::SDR => "SDR",
            TypeId::ForeignSh => "Foreign Sh.",
            TypeId::NYRegShrs => "NY Reg Shrs",
            TypeId::ETP => "ETP",
            TypeId::PUBLIC => "PUBLIC",
            TypeId::LtdPart => "Ltd Part",
            TypeId::EquityWRT => "Equity WRT",
            TypeId::ADR => "ADR",
            TypeId::Receipt => "Receipt",
            TypeId::None => "",
        };
        v.to_string()
    }
}
