namespace SqlDynamite.Common

open System
open System.Data
open StackExchange.Redis

type RedisMetadataFinder() =
    inherit MetadataFinder()

    override this.GetDatabaseList (scname:string) : string list =
        let parts = this._connection.ConnectionString.Split(';')
        let cs = parts.[0].Split(':')
        let db = if String.IsNullOrWhiteSpace(parts.[1]) then 0 else Int32.Parse(parts.[1].Replace("db", ""))
        let port = if cs.Length = 2 then Int32.Parse(cs.[1]) else 6379
        let password = if parts.Length = 3 then parts.[2].Replace("Password=", "") else ""
        let co = new ConfigurationOptions()
        co.EndPoints.Add(cs.[0], port)
        co.DefaultDatabase <- db
        if not (String.IsNullOrWhiteSpace(password)) then co.Password <- password
        let cm = ConnectionMultiplexer.Connect(co)
        let server = cm.GetServer(cs.[0], port)
        let dbcount = server.DatabaseCount
        let rec loop n acc =
            if n > 0 then
                let m = n - 1
                loop m ("db" + m.ToString() :: acc)
            else
                acc
        loop dbcount []

    override this.Compose(tablename:string, fields:DataTable, keys:DataTable, checks:DataTable) : string =
        raise (NotImplementedException())

    override this.GetDefColumns(name:string, objtype:ObjectType) : DataTable list =
        raise (NotImplementedException())

    override this.GetNameByTextColumns(searchStr:string, types:ObjectType list, caseSensitive:bool) : string =
        searchStr

    override this.GetTextColumns(name:string, objtype:ObjectType) : string list =
        raise (NotImplementedException())

    override this.GenerateNameScript(search:string, types:ObjectType list, caseSensitive:bool) : string =
        search

    override this.GenerateSearchScript(search:string, caseSensitive:bool) : string =
        search

    override this.GetForeignKeyDefinition(constraintName:string) : string =
        raise (NotImplementedException())

    override this.GetPrimaryKeyDefinition(constraintName:string) : string =
        raise (NotImplementedException())

    override this.GetIndexDefinition(constraintName:string) : string =
        raise (NotImplementedException())

    override this.GetSequenceDefinition(sequenceName:string) : string =
        raise (NotImplementedException())

    override this.GetSynonymDefinition(synonymName:string) : string =
        raise (NotImplementedException())

    override this.GetTypeDefinition(typeName:string) : string =
        raise (NotImplementedException())

    override this.GetJobDefinition(jobName:string) : string =
        raise (NotImplementedException())

    override this.GetReportDefinition(reportName:string) : string =
        raise (NotImplementedException())

    override this.GetExtendedProcedureDefinition(procName:string) : string =
        raise (NotImplementedException())

    override this.GetExtendedTriggerDefinition(triggerName:string) : string =
        raise (NotImplementedException())

    member this.GetStringValue(keyName:string) : string =
        let parts = this._connection.ConnectionString.Split(';')
        let cs = parts.[0].Split(':')
        let db = if String.IsNullOrWhiteSpace(parts.[1]) then 0 else Int32.Parse(parts.[1].Replace("db", ""))
        let port = if cs.Length = 2 then Int32.Parse(cs.[1]) else 6379
        let password = if parts.Length = 3 then parts.[2].Replace("Password=", "") else ""
        let co = new ConfigurationOptions()
        co.EndPoints.Add(cs.[0], port)
        co.DefaultDatabase <- db
        if not (String.IsNullOrWhiteSpace(password)) then co.Password <- password
        let cm = ConnectionMultiplexer.Connect(co)
        cm.GetDatabase().StringGet(keyName).ToString()

    member this.GetListValue(keyName:string) : string =
        let parts = this._connection.ConnectionString.Split(';')
        let cs = parts.[0].Split(':')
        let db = if String.IsNullOrWhiteSpace(parts.[1]) then 0 else Int32.Parse(parts.[1].Replace("db", ""))
        let port = if cs.Length = 2 then Int32.Parse(cs.[1]) else 6379
        let password = if parts.Length = 3 then parts.[2].Replace("Password=", "") else ""
        let co = new ConfigurationOptions()
        co.EndPoints.Add(cs.[0], port)
        co.DefaultDatabase <- db
        if not (String.IsNullOrWhiteSpace(password)) then co.Password <- password
        let cm = ConnectionMultiplexer.Connect(co)
        let lst = cm.GetDatabase().ListRange(keyName)
        String.Join(Environment.NewLine, lst)

    member this.GetHashValue(keyName:string) : string =
        let parts = this._connection.ConnectionString.Split(';')
        let cs = parts.[0].Split(':')
        let db = if String.IsNullOrWhiteSpace(parts.[1]) then 0 else Int32.Parse(parts.[1].Replace("db", ""))
        let port = if cs.Length = 2 then Int32.Parse(cs.[1]) else 6379
        let password = if parts.Length = 3 then parts.[2].Replace("Password=", "") else ""
        let co = new ConfigurationOptions()
        co.EndPoints.Add(cs.[0], port)
        co.DefaultDatabase <- db
        if not (String.IsNullOrWhiteSpace(password)) then co.Password <- password
        let cm = ConnectionMultiplexer.Connect(co)
        let lst = cm.GetDatabase().HashGetAll(keyName)
        String.Join(Environment.NewLine, lst)

    member this.GetSetValue(keyName:string) : string =
        let parts = this._connection.ConnectionString.Split(';')
        let cs = parts.[0].Split(':')
        let db = if String.IsNullOrWhiteSpace(parts.[1]) then 0 else Int32.Parse(parts.[1].Replace("db", ""))
        let port = if cs.Length = 2 then Int32.Parse(cs.[1]) else 6379
        let password = if parts.Length = 3 then parts.[2].Replace("Password=", "") else ""
        let co = new ConfigurationOptions()
        co.EndPoints.Add(cs.[0], port)
        co.DefaultDatabase <- db
        if not (String.IsNullOrWhiteSpace(password)) then co.Password <- password
        let cm = ConnectionMultiplexer.Connect(co)
        let lst = cm.GetDatabase().SetMembers(keyName)
        String.Join(Environment.NewLine, lst)

    member this.GetSortedSetValue(keyName:string) : string =
        let parts = this._connection.ConnectionString.Split(';')
        let cs = parts.[0].Split(':')
        let db = if String.IsNullOrWhiteSpace(parts.[1]) then 0 else Int32.Parse(parts.[1].Replace("db", ""))
        let port = if cs.Length = 2 then Int32.Parse(cs.[1]) else 6379
        let password = if parts.Length = 3 then parts.[2].Replace("Password=", "") else ""
        let co = new ConfigurationOptions()
        co.EndPoints.Add(cs.[0], port)
        co.DefaultDatabase <- db
        if not (String.IsNullOrWhiteSpace(password)) then co.Password <- password
        let cm = ConnectionMultiplexer.Connect(co)
        let lst = cm.GetDatabase().SortedSetRangeByRankWithScores(keyName)
        String.Join(Environment.NewLine, lst)

    member this.GetStreamValue(keyName:string) : string =
        let parts = this._connection.ConnectionString.Split(';')
        let cs = parts.[0].Split(':')
        let db = if String.IsNullOrWhiteSpace(parts.[1]) then 0 else Int32.Parse(parts.[1].Replace("db", ""))
        let port = if cs.Length = 2 then Int32.Parse(cs.[1]) else 6379
        let password = if parts.Length = 3 then parts.[2].Replace("Password=", "") else ""
        let co = new ConfigurationOptions()
        co.EndPoints.Add(cs.[0], port)
        co.DefaultDatabase <- db
        if not (String.IsNullOrWhiteSpace(password)) then co.Password <- password
        let cm = ConnectionMultiplexer.Connect(co)
        let lst = cm.GetDatabase().StreamRange(keyName)
        let rec getStreamEntryValues (arr:NameValueEntry array) n acc =
            if n > 0 then
                let item = arr.[n - 1].Name.ToString().Trim() + " : " + arr.[n - 1].Value.ToString().Trim()
                getStreamEntryValues arr (n - 1) (item :: acc)
            else
                acc
        let rec loop n acc =
            if n > 0 then
                let item = getStreamEntryValues lst.[n - 1].Values lst.[n - 1].Values.Length []
                loop (n - 1) (item :: acc)
            else
                acc
        String.Join(Environment.NewLine, loop lst.Length [])
