package com.jkanetwork.st.frasesdeanime

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import org.jetbrains.anko.db.*
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStream
import java.util.Calendar
import android.util.Log

/**
 * Created by kprkpr on 18/07/17.
 */

/** ctx, DB.NAME, null, DB.Version */
class SQLiteHelper(ctx: Context) : ManagedSQLiteOpenHelper(ctx, "otaku.sqlite", null, 8) {
    val context = ctx
    val db = this.getWritableDatabase()

    // Hacer que los números al pasar a String tengan X digitos
    fun Int.format(digits: Int) = java.lang.String.format("%0${digits}d", this)
    companion object {
        private var instance: SQLiteHelper? = null

        @Synchronized
        fun getInstance(ctx: Context): SQLiteHelper {
            if (instance == null) {
                instance = SQLiteHelper(ctx.applicationContext)
            }
            return instance!!
        }
    }

    override fun onCreate(db: SQLiteDatabase) {
        // Here you create tables
        db.execSQL("CREATE TABLE FRASESVI (" +
                "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
                "TDay TEXT NOT NULL UNIQUE," +
                "IDFrase INTEGER)")
        db.createTable("FRASESFAV", true,
                "IDFrase" to INTEGER + UNIQUE)
        db.createTable("ANIMESON", true,
                "IDAnime" to INTEGER + UNIQUE)

        //Load animes and sentences
        var queries: List<String> = readSqldata(R.raw.loadsqlfile).split(";\n");
        for (query in queries){
            if (!query.isBlank())
                db.execSQL(query);
        }
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        // Here you can upgrade tables, as usual
        var queries: List<String> = readSqldata(R.raw.loadsqlfile).split(";\n");
        for (query in queries){
            if (!query.isBlank())
                db.execSQL(query);
        }
    }


    fun readSqldata(res: Int): String {
        //getting the file
        val inputStream: InputStream
        inputStream = context.getResources().openRawResource(res)
        val byteArrayOutputStream = ByteArrayOutputStream()
        try {
            var i = inputStream.read()
            while (i != -1) {
                byteArrayOutputStream.write(i)
                i = inputStream.read()
            }
            inputStream.close()

        } catch (e: IOException) {
            e.printStackTrace()
        }
        return byteArrayOutputStream.toString()
    }


    /** Returns a boolean saying if a sentence is faved or not */
    fun getFav (IDFrase: Int): Boolean {
        val query = db.rawQuery("SELECT IDFrase FROM FRASESFAV WHERE IDFrase = '$IDFrase'", null)
        val res = query.getCount()
        query.close()
        if (res > 0){
            return true
        }else{
            return false
        }
    }

    /** Changes the state of fav of a sentence
     * @param IDFrase: Sentence
     */
    fun setFav (IDFrase: Int) {
        if (getFav(IDFrase) == false){
            db.insert("FRASESFAV","IDFrase" to IDFrase)
        }else{
            db.execSQL("DELETE FROM FRASESFAV WHERE IDFrase='$IDFrase'")
        }
    }

    fun getSentenceFromIDF (IDFrase: Int): String {
        if (IDFrase == 0){ return "No hay más frases disponibles..."}
        if (IDFrase == -1){ return "No puedes ver aún esta frase"}
        if (IDFrase == -2){ return "Error inesperado"}
        val c = db.rawQuery("SELECT Frase FROM FRASES WHERE IDFrase = '$IDFrase'", null)
        c.moveToFirst()
        val ret = c.getString(0)
        c.close()
        return ret
    }

    fun getAnimeFromIDF (IDFrase: Int): String {
        if (IDFrase <= 0){ return "..."}
        val c = db.rawQuery("SELECT Name FROM ANIMES WHERE IDAnime = (SELECT IDAnime FROM FRASES WHERE IDFrase = '$IDFrase')", null)
        c.moveToFirst()
        val ret = c.getString(0)
        c.close()
        return ret
    }

    fun getIDAnimeFromName (Name: String): Int {
        var query = db.select("ANIMES", "IDAnime").whereArgs("Name = '$Name'")
        return query.parseSingle(IntParser)
    }



    fun getIDFrase (year: Int,month: Int, day: Int): Int {
        val cal = Calendar.getInstance()
        /* First Integer to Strings of format YYYYMMDD for store and compare */
        val diaArg = "${year}${month.format(2)}${day.format(2)}"
        val diaAct = "${cal.get(Calendar.YEAR)}${(cal.get(Calendar.MONTH)+1).format(2)}${cal.get(Calendar.DAY_OF_MONTH).format(2)}"

        /* Query db looking for the sentence. If there are not loaded yet, see (else if) if they can show a new one, if criteria is true. If not, not show sentence */
        var query = db.rawQuery("SELECT IDFrase FROM FRASESVI WHERE TDay = '$diaArg'", null)
        if (query.getCount() > 0){
            query.moveToFirst()
            val ret = query.getInt(0)
            query.close()
            return ret
        }else if (diaArg == diaAct || diaArg.toInt() < diaAct.toInt() && db.rawQuery("SELECT IDFrase FROM FRASESVI WHERE Tday < '$diaArg'", null).count > 0 ) {
            try {
                query = db.rawQuery("SELECT IDFrase FROM FRASES WHERE IDAnime IN (SELECT IDAnime FROM ANIMESON) AND IDFrase NOT IN (SELECT IDFrase FROM FRASESVI) ORDER BY RANDOM() LIMIT 1", null)
                query.moveToFirst()
                db.insert("FRASESVI",
                        "TDay" to diaArg,
                        "IDFrase" to query.getString(0))
                val ret = query.getInt(0)
                query.close()
                return ret
            }
            catch (e: Exception) {
                return 0 //No more sentences
            }
        }else{
            return -1 //Day not yet
        }
    }

    fun getIDFraseHoy(): Int {
        val cal = Calendar.getInstance()
        //Month + 1 because Android starts with month=0
        return getIDFrase(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH))
    }

    fun getAllIDFavs(): Array<Int>{
        var query = db.select("FRASESFAV", "IDFrase")
        var list = query.parseList(IntParser)
        return list.toTypedArray()
    }

    fun getAllAnimeIDs(): Array<Int>{
        var query = db.select("ANIMES", "IDAnime").orderBy("Name", SqlOrderDirection.ASC)
        var list = query.parseList(IntParser)
        return list.toTypedArray()
    }

    fun getAllAnimeNames(): Array<String>{
        var query = db.select("ANIMES", "Name").orderBy("Name", SqlOrderDirection.ASC)
        var list = query.parseList(StringParser)
        return list.toTypedArray()
    }

    /** Return if the anime asked by [IDA] is selected */
    fun getAnimeSel(IDA: Int): Boolean{
        val query = db.rawQuery("SELECT IDAnime FROM ANIMESON WHERE IDAnime = '$IDA'", null)
        val res = query.getCount()
        query.close()
        if (res > 0){
            return true
        }else{
            return false
        }
    }

    /** Changes the state of a selected or not anime
     * @param IDAnime: Anime
     */
    fun setAnimeSel (IDAnime: Int) {
        if (getAnimeSel(IDAnime) == false){
            db.insert("ANIMESON","IDAnime" to IDAnime)
        }else{
            db.execSQL("DELETE FROM ANIMESON WHERE IDAnime='$IDAnime'")
        }
    }


    /** Return how much animes are selected (For knowing if 0) */
    fun getCountAnimeSel(): Int{
        val query = db.rawQuery("SELECT COUNT(*) FROM ANIMESON", null)
        query.moveToFirst()
        val ret = query.getInt(0)
        query.close();
        return ret;
    }

    /** Deletes the sentence of the day passed as argument yearS,monthS, dayS
     * @param year: Year selected
     * @param month: Month selected
     * @param day: Day selected
     */
    fun delSentence (year: Int, month: Int, day: Int) {
        val diaArg = "${year}${month.format(2)}${day.format(2)}"
        db.execSQL("DELETE FROM FRASESVI WHERE TDay='$diaArg'")
    }


    /** This funcion selects or desselects all animes from selected to show */
    fun setAllAnimeSel(){
        var selectAll = getAllAnimeSel(); //Know if anyone is select (true/false)
        //First, unset all, and after that, select all if they were not before. (Why? Because if someone are select, inserting again will crash)
        db.execSQL("DELETE FROM ANIMESON")
        if (selectAll == false){ //Set all
            var animeIDs = getAllAnimeIDs()

            for (pos in animeIDs){
                db.insert("ANIMESON",
                        "IDAnime" to animeIDs[pos-1]) //Pos is a count, arrays start at 0
            }
        }
    }

    /** It returns if all animes are selected or not */
    fun getAllAnimeSel(): Boolean{
        var set = getCountAnimeSel();
        var countanime = getAllAnimeIDs().size;
        if (set == countanime){
            return true;
        }else{
            return false;
        }

    }


    /** It returns to program that this sentence can't be seen */
    fun getSentenceCanBeSeen(year: Int,month: Int, day: Int): Boolean {
        //TODO, return 0 when if check this sentence will be "nothing", for disable button
        return true;
    }

}

// Access property for Context
val Context.database: SQLiteHelper
    get() = SQLiteHelper.getInstance(applicationContext)