namespace SqlDynamite.Common

open System
open System.Collections.Generic
open System.Data
open System.Text

type CassandraMetadataFinder() =
    inherit MetadataFinder()

    override this.GetDatabaseList (scname:string) : string list =
        let dbs = this.CreateDataSet("select keyspace_name from system_schema.keyspaces").Tables.Item(0)
        let rec loop n acc =
            if n > 0 then
                let item = dbs.Rows.Item(n - 1).Item(0).ToString().Trim()
                loop (n - 1) (item :: acc)
            else
                acc
        loop dbs.Rows.Count []

    override this.Compose(tablename:string, fields:DataTable, keys:DataTable, checks:DataTable) : string =
        let definition (record:DataRow) =
            "\n\t" + record.Item("column_name").ToString() + " " + record.Item("type").ToString() + ","
        let result = "CREATE TABLE " + tablename + " ("
        let rec loop n acc =
            if n > 0 then
                loop (n - 1) (definition(fields.Rows.Item(n - 1)) :: acc)
            else
                acc
        String.Join("",[result;String.Join("",loop fields.Rows.Count []).TrimEnd(',');");"])

    override this.GetDefColumns(name:string, objtype:ObjectType) : DataTable list =
        let keyspace = if this._connection.ConnectionString.ToLower().Contains("default keyspace=") then this._connection.ConnectionString.ToLower().Replace("default keyspace=", "").Split(';').[0] else null
        let ks = if String.IsNullOrWhiteSpace(keyspace) then "" else "and KEYSPACE_NAME = '" + keyspace + "'"
        let script = String.Format("select COLUMN_NAME, TYPE from SYSTEM_SCHEMA.COLUMNS where TABLE_NAME = '{0}' {1} ALLOW FILTERING;", name, ks)
        let columns = this.CreateDataSet(script.ToString()).Tables.Item(0)
        [columns; null; null]

    override this.GetTextColumns(name:string, objtype:ObjectType) : string list =
        let keyspace = if this._connection.ConnectionString.ToLower().Contains("default keyspace=") then this._connection.ConnectionString.ToLower().Replace("default keyspace=", "").Split(';').[0] else null
        let ks = if String.IsNullOrWhiteSpace(keyspace) then "" else "and KEYSPACE_NAME = '" + keyspace + "'"
        let query =
            if objtype = ObjectType.VIEW then
                "select WHERE_CLAUSE from SYSTEM_SCHEMA.VIEWS where VIEW_NAME = '"
            elif objtype = ObjectType.FUNCTION then
                "select BODY from SYSTEM_SCHEMA.FUNCTIONS where FUNCTION_NAME = '"
            else ""
        let lst = this.CreateDataSet(query + name + "' " + ks + " ALLOW FILTERING;").Tables.Item(0)
        let rec loop n acc =
            if n > 0 then
                loop (n - 1) (lst.Rows.Item(n - 1).Item(0).ToString() :: acc)
            else
                acc
        loop lst.Rows.Count []

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

    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 =
        let keyspace = if this._connection.ConnectionString.ToLower().Contains("default keyspace=") then this._connection.ConnectionString.ToLower().Replace("default keyspace=", "").Split(';').[0] else null
        let ks = if String.IsNullOrWhiteSpace(keyspace) then "" else "and KEYSPACE_NAME = '" + keyspace + "'"
        let script = String.Format("select TABLE_NAME, INDEX_NAME, OPTIONS from SYSTEM_SCHEMA.INDEXES where INDEX_NAME = '{0}' {1} ALLOW FILTERING;", constraintName, ks)
        let tbl = this.CreateDataSet(script.ToString()).Tables.Item(0)
        let tableName = tbl.Rows.Item(0).Item("TABLE_NAME").ToString()
        let columns = tbl.Rows.Item(0).Item("OPTIONS") :?> SortedDictionary<string, string>
        let sb = StringBuilder()
        for item in columns do
            sb.Append(item.Value) |> ignore
            sb.Append(',') |> ignore
        "CREATE INDEX " + constraintName + " ON " + keyspace + "." + tableName + "(" + sb.ToString().TrimEnd(',') + ");"

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

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

    override this.GetTypeDefinition(typeName:string) : string =
        let keyspace = if this._connection.ConnectionString.ToLower().Contains("default keyspace=") then this._connection.ConnectionString.ToLower().Replace("default keyspace=", "").Split(';').[0] else null
        let ks = if String.IsNullOrWhiteSpace(keyspace) then "" else "and KEYSPACE_NAME = '" + keyspace + "'"
        let script = String.Format("select TYPE_NAME, FIELD_NAMES, FIELD_TYPES from SYSTEM_SCHEMA.TYPES where TYPE_NAME = '{0}' {1} ALLOW FILTERING;", typeName, ks)
        let tbl = this.CreateDataSet(script.ToString()).Tables.Item(0)
        let fieldNames = tbl.Rows.Item(0).Item("FIELD_NAMES") :?> string array
        let fieldTypes = tbl.Rows.Item(0).Item("FIELD_TYPES") :?> string array
        let rec loop n acc =
            if n > 1 then
                loop (n - 1) (acc + "\n\t" + fieldNames.[n - 1] + " " + fieldTypes.[n - 1] + ",")
            elif n = 1 then
                loop (n - 1) (acc + "\n\t" + fieldNames.[n - 1] + " " + fieldTypes.[n - 1])
            else
                acc
        "CREATE TYPE " + keyspace + "." + typeName + "(" + (loop fieldNames.Length String.Empty) + ");"

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

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

    override this.GetExtendedProcedureDefinition(procName:string) : string =
        let keyspace = if this._connection.ConnectionString.ToLower().Contains("default keyspace=") then this._connection.ConnectionString.ToLower().Replace("default keyspace=", "").Split(';').[0] else null
        let ks = if String.IsNullOrWhiteSpace(keyspace) then "" else "and KEYSPACE_NAME = '" + keyspace + "'"
        let query = "select AGGREGATE_NAME, ARGUMENT_TYPES, STATE_FUNC, STATE_TYPE, FINAL_FUNC, INITCOND from SYSTEM_SCHEMA.AGGREGATES where AGGREGATE_NAME = '"
        let row = this.CreateDataSet(query + procName + "' " + ks + " ALLOW FILTERING;").Tables.Item(0).Rows.Item(0)
        let argumentTypes = row.Item("ARGUMENT_TYPES") :?> string array
        let rec loop n acc =
            if n > 0 then
                loop (n - 1) (argumentTypes.[n - 1] :: acc)
            else
                acc
        let argumentTypesStr = String.Join(",",loop argumentTypes.Length [])
        "CREATE AGGREGATE IF NOT EXISTS " + row.Item("AGGREGATE_NAME").ToString() + " (" + argumentTypesStr + ") SFUNC " + row.Item("STATE_FUNC").ToString() + " STYPE " + row.Item("STATE_TYPE").ToString() + " FINALFUNC " + row.Item("FINAL_FUNC").ToString() + " INITCOND " + row.Item("INITCOND").ToString() + ";"

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