using System.Globalization;

namespace Fast.Web.Models;

public class DataMineSettlementRecord
{
    public DateOnly? BizDt { get; set; }
    public string Sym { get; set; } = "";
    public string ID { get; set; } = "";
    public decimal? StrkPx { get; set; }
    public string SecTyp { get; set; } = "";
    public DateOnly? MMY { get; set; }
    public DateOnly? MatDt { get; set; }
    public DataMinePutCall? PutCall { get; set; }
    public string Exch { get; set; } = "";
    public string Desc { get; set; } = "";
    public DateOnly? LastTrdDt { get; set; }
    public decimal? BidPrice { get; set; }
    public decimal? OpeningPrice { get; set; }
    public decimal? SettlePrice { get; set; }
    public decimal? SettleDelta { get; set; }
    public decimal? HighLimit { get; set; }
    public decimal? LowLimit { get; set; }
    public decimal? DHighPrice { get; set; }
    public decimal? DLowPrice { get; set; }
    public decimal? HighBid { get; set; }
    public decimal? LowBid { get; set; }
    public int? PrevDayVol { get; set; }
    public int? PrevDayOI { get; set; }
    public decimal? FixingPrice { get; set; }
    public string UndlyExch { get; set; } = "";
    public string UndlyID { get; set; } = "";
    public string UndlySecTyp { get; set; } = "";
    public DateOnly? UndlyMMY { get; set; }
    public string BankBusDay { get; set; } = "";

    public DataMineSettlementRecord(string csvLine)
    {
        var values = csvLine.Split(',');

        Sym = values[1].Trim('"');

        try
        {
            BizDt = ParseDate(values[0]);
            ID = ParseString(values[2]);
            StrkPx = ParseDecimal(values[3]);
            SecTyp = ParseString(values[4]);
            MMY = ParseDate(values[5]);
            MatDt = ParseDate(values[6]);
            PutCall = ParsePutCall(values[7]);
            Exch = ParseString(values[8]);
            Desc = ParseString(values[9]);
            LastTrdDt = ParseDate(values[10]);
            BidPrice = ParseDecimal(values[11]);
            OpeningPrice = ParseDecimal(values[12]);
            SettlePrice = ParseDecimal(values[13]);
            SettleDelta = ParseDecimal(values[14]);
            HighLimit = ParseDecimal(values[15]);
            LowLimit = ParseDecimal(values[16]);
            DHighPrice = ParseDecimal(values[17]);
            DLowPrice = ParseDecimal(values[18]);
            HighBid = ParseDecimal(values[19]);
            LowBid = ParseDecimal(values[20]);
            PrevDayVol = ParseInt(values[21]);
            PrevDayOI = ParseInt(values[22]);
            FixingPrice = ParseDecimal(values[23]);
            UndlyExch = ParseString(values[24]);
            UndlyID = ParseString(values[25]);
            UndlySecTyp = ParseString(values[26]);
            UndlyMMY = ParseDate(values[27]);
            BankBusDay = ParseString(values[28]);
        }
        catch (Exception ex)
        {
            throw new Exception($"Error parsing settlement record for {Sym}", ex);
        }
    }

    public enum DataMinePutCall
    {
        Put = 0,
        Call = 1
    }

    private static string MyTrim(string value)
    {
        return value.Trim('"').Trim();
    }

    private static string ParseString(string value)
    {
        value = MyTrim(value);
        return string.IsNullOrEmpty(value) ? "" : value;
    }

    private static decimal? ParseDecimal(string value)
    {
        value = MyTrim(value);
        return string.IsNullOrEmpty(value) ? null : decimal.Parse(value, CultureInfo.InvariantCulture);
    }

    private static DateOnly? ParseDate(string value)
    {
        DateOnly? returnVal = null;
        value = MyTrim(value);
        if (!string.IsNullOrEmpty(value))
        {
            if (value.Length == 10)
                returnVal = DateOnly.ParseExact(value, "yyyy-MM-dd", CultureInfo.InvariantCulture);
            else if (value.Length == 8)
                returnVal = DateOnly.ParseExact(value, "yyyyMMdd", CultureInfo.InvariantCulture);
            else if (value.Length == 6)
                returnVal = DateOnly.ParseExact(value, "yyyyMM", CultureInfo.InvariantCulture);
            else if (value.Length == 4) //for 2 digit year followed by 2 digit month
            {
                CultureInfo cultureInfo = (CultureInfo)CultureInfo.InvariantCulture.Clone();
                cultureInfo.Calendar.TwoDigitYearMax = 2099; //so that 2 digit years are parsed as 20xx instead of 19xx
                returnVal = DateOnly.ParseExact(value, "yyMM", CultureInfo.InvariantCulture);
            }
            else
                throw new Exception($"Invalid date format: {value}");
        }

        return returnVal;
    }

    private static int? ParseInt(string value)
    {
        value = MyTrim(value);
        return string.IsNullOrEmpty(value) ? null : int.Parse(value);
    }

    private static DataMinePutCall? ParsePutCall(string value)
    {
        value = MyTrim(value);
        return string.IsNullOrEmpty(value) ? null : (DataMinePutCall)int.Parse(value);
    }
}