package com.tomastc.smartwatchclient.lib;

import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.widget.Toast;

import androidx.documentfile.provider.DocumentFile;

import com.tomastc.smartwatchclient.R;
import com.tomastc.smartwatchclient.lib.common.AsyncFtpClient;
import com.tomastc.smartwatchclient.lib.common.AsyncHttpClient;
import com.tomastc.smartwatchclient.lib.common.AsyncHttpClientImage;
import com.tomastc.smartwatchclient.lib.common.FileUtil;
import com.tomastc.smartwatchclient.lib.common.Utils;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class Settings {
    
    private static Context context;

    private static final String SETTING_PATH = "skt";
    private static final String LOG_PATH = "log";

    private static final String MANAGEMENT_INFO = "MngInfo.csv";
    private static final String SETTING_INFO = "Settings.csv";
    private static final String USER_INFO = "UserInfo.csv";
    private static final String STATE_INFO = "StateInfo.dat";
    private static final String JOB_INFO = "JobInfo.dat";

    private static Map<String, String> mgmtList = new HashMap<String, String>();
    private static Map<String, String> settingList = new HashMap<String, String>();
    private static Map<String, String> usrList = new HashMap<String, String>();

    private static UserInfo userInfoX = null;
    private static Bitmap background = null;

    private static String presettings = null;

    public static String getPresettings() {
        return presettings;
    }
    public static JSONObject getPresettingsObject() throws JSONException {
        JSONArray jsonArray = new JSONArray(presettings);
        JSONObject json = jsonArray.getJSONObject(0);
        return json;
    }

    public static void setPresettings(String presettings) {
        Settings.presettings = presettings;
    }

    public static void readManagementFile(File dir) throws IOException {
        try {
            // clear list first
            mgmtList.clear();

            String raw = (new FileUtil(context)).readFile(MANAGEMENT_INFO, dir.getAbsolutePath());

            String[] lines = raw.split(System.getProperty("line.separator"));
            int i = 0;
            for (String line : lines) {
                Log.d(Settings.context.getString(R.string.tag), "read line:" + line);
                String[] values = line.split(",");
                try {
                    mgmtList.put(values[0], values[1]);
                    i++;
                } catch (Exception e) {
                    Log.d(Settings.context.getString(R.string.tag), "line format error!");
                }
            }

            if (lines.length == 0 || i==0) {
                throw new IOException("file format error");
            }
        } catch (IOException ioe) {
            Log.d(Settings.context.getString(R.string.tag), "cannot read file, error:" + ioe.getMessage());
            throw ioe;
        }
    }

    public static void readManagementFile(DocumentFile path, ContentResolver contentResolver) {

        // read manager file
        Log.d(Settings.context.getString(R.string.tag), "open file:" + MANAGEMENT_INFO);
        DocumentFile mgmtFile = path.findFile(MANAGEMENT_INFO);
        if (mgmtFile.exists() && mgmtFile.canRead()) {
            try {
                String raw = (new FileUtil(context)).readTextFromUri(mgmtFile.getUri(), contentResolver);
                Log.d(Settings.context.getString(R.string.tag), "file content:" + raw);

                String[] lines = raw.split(System.getProperty("line.separator"));
                for (String line : lines) {
                    String[] values = line.split("=");
                    mgmtList.put(values[0], values[1]);
                }
            } catch (IOException ioe) {
                Log.d(Settings.context.getString(R.string.tag), "cannot read file, error:" + ioe.getMessage());
            }
        } else {
            Log.i("SKT", "file not found![" + MANAGEMENT_INFO + "]");
        }

    }

    public static void readSettingFile(File dir) {
        try {
            // clear list first
            settingList.clear();

            String raw = (new FileUtil(context)).readFile(SETTING_INFO, dir.getAbsolutePath());

            String[] lines = raw.split(System.getProperty("line.separator"));
            int i = 0;
            for (String line : lines) {
                Log.d(Settings.context.getString(R.string.tag), "read line:" + line);
                String[] values = line.split(",");
                try {
                    settingList.put(values[0], values[1]);
                    i++;
                } catch (Exception e) {
                    Log.d(Settings.context.getString(R.string.tag), "line format error!");
                }
            }

            if (lines.length == 0 || i==0) {
                throw new IOException("file format error");
            }
        } catch (IOException ioe) {
            Log.d(Settings.context.getString(R.string.tag), "cannot read file, error:" + ioe.getMessage());
        }
    }

    public static void readSettingFile(DocumentFile path, ContentResolver contentResolver) {

        // read setting file
        Log.d(Settings.context.getString(R.string.tag), "open file:" + SETTING_INFO);
        DocumentFile settingInfoFile = path.findFile(SETTING_INFO);
        if (settingInfoFile.exists() && settingInfoFile.canRead()) {
            try {
                String raw = (new FileUtil(context)).readTextFromUri(settingInfoFile.getUri(), contentResolver);
                Log.d(Settings.context.getString(R.string.tag), "file content:" + raw);

                String[] lines = raw.split(System.getProperty("line.separator"));
                int i = 0;
                for (String line : lines) {
                    String[] values = line.split(",");
                    settingList.put(values[0], values[1]);
                }
            } catch (IOException ioe) {
                Log.d(Settings.context.getString(R.string.tag), "cannot read file, error:" + ioe.getMessage());
            }
        } else {
            Log.i("SKT", "file not found![" + SETTING_INFO + "]");
        }
    }

    public static void readUserInfoFile(File dir) throws IOException {
        try {
            // clear list first
            usrList.clear();

            String raw = (new FileUtil(context)).readFile(USER_INFO, dir.getAbsolutePath());

            String[] lines = raw.split(System.getProperty("line.separator"));
            int i = 0;
            for (String line : lines) {
                Log.d(Settings.context.getString(R.string.tag), "read line:" + line);
                String[] values = line.split(",");
                try {
                    usrList.put(values[0], values[1]);
                    i++;
                } catch (Exception e) {
                    Log.d(Settings.context.getString(R.string.tag), "line format error!");
                }
            }

            if (lines.length == 0 || i==0) {
                throw new IOException("file format error");
            }
        } catch (IOException ioe) {
            Log.d(Settings.context.getString(R.string.tag), "cannot read file, error:" + ioe.getMessage());
            throw ioe;
        }
    }

    public static void readUserInfoFile(DocumentFile path, ContentResolver contentResolver) {

        // read user info file
        Log.d(Settings.context.getString(R.string.tag), "open file:" + USER_INFO);
        DocumentFile userInfoFile = path.findFile(USER_INFO);
        if (userInfoFile.exists() && userInfoFile.canRead()) {
            try {
                String raw = (new FileUtil(context)).readTextFromUri(userInfoFile.getUri(), contentResolver);
                Log.d(Settings.context.getString(R.string.tag), "file content:" + raw);

                String[] lines = raw.split(System.getProperty("line.separator"));
                for (String line : lines) {
                    String[] values = line.split(",");
                    usrList.put(values[0], values[1]);
                }
            } catch (IOException ioe) {
                Log.d(Settings.context.getString(R.string.tag), "cannot read file, error:" + ioe.getMessage());
            }
        } else {
            Log.i("SKT", "file not found![" + USER_INFO + "]");
        }
    }

    public static void updateSettingsFile(Map<String, String> settingList, String path) {
        Settings.settingList = settingList;

        Log.d(Settings.context.getString(R.string.tag), "write settings file...");
        try {
            (new FileUtil(context)).writeFile(SETTING_INFO, path, Utils.mapToCsv((HashMap) settingList));
        } catch (IOException ioe) {
            Log.d(Settings.context.getString(R.string.tag), "cannot write file, error:" + ioe.getMessage());
        }
    }

    public static void init(Context context) {
        Settings.context = context;
        
        readSettingFile(context.getFilesDir());

        String localDir = context.getFilesDir().getAbsolutePath();

        // load manager setting
        try {
            readManagementFile(context.getFilesDir());

            if (Settings.getMgmtList().containsKey("background-file")) {
                String filename = Settings.getMgmtList().get("background-file");

                File img = new File(context.getFilesDir().getAbsolutePath() + "/" + filename);
                if (!img.exists()) {

                    // try download

                    // send JSON request
                    JSONObject json = new JSONObject();
                    json.put("type", Settings.getMgmtList().get("background-type"));
                    json.put("file", Settings.getMgmtList().get("background-file"));

                    new AsyncHttpClientImage(context
                            , Settings.getMgmtList().get("background-web")
                            , json.toString()
                    ) {
                        @Override
                        public void onFinished(Bitmap bmp, int resp_code) {
                            String filename = Settings.getMgmtList().get("background-file");

                            try (FileOutputStream out = context.openFileOutput(filename, Context.MODE_PRIVATE)) {
                                bmp.compress(Bitmap.CompressFormat.PNG, 100, out); // bmp is your Bitmap instance
                                // PNG is a lossless format, the compression factor (100) is ignored
                            } catch (IOException e) {
                                e.printStackTrace();
                            }

                            setBackground(bmp);
                        }
                    }
                            .execute();
                } else {

                    // Load bitmap from file
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
                    setBackground(BitmapFactory.decodeFile(img.getAbsolutePath(), options));
                }
            }
        } catch (Exception ioe) {
            try {
                if (Settings.getServerMode().equalsIgnoreCase("http")) {
                    new AsyncHttpClient(
                            context
                            ,Settings.getServer() + "/" + Settings.getPath() + "/" + Settings.getManagementInfo()
                            , ""
                    ) {
                        @Override
                        public void onFinished(String response, int resp_code) {
                            Log.d(Settings.context.getString(R.string.tag), "response: " + response);
                            if (resp_code == 200) {
                                Log.d(Settings.context.getString(R.string.tag), "write management info file...");
                                try {
                                    (new FileUtil(context)).writeFile(MANAGEMENT_INFO, context.getFilesDir().getAbsolutePath(), response);
                                } catch (IOException ioe) {
                                    Log.d(Settings.context.getString(R.string.tag), "cannot write file, error:" + ioe.getMessage());
                                }
                            }
                        }
                    }
                            .execute();
                } else {
                    new AsyncFtpClient(new AsyncFtpClient.TaskListener() {
                        @Override
                        public void onFinished(String result) {
                            // Do Something after the task has finished
                            try {
                                readManagementFile(context.getFilesDir());
                            } catch (IOException e) {
                                Log.d(Settings.context.getString(R.string.tag), "read Manager file error");
                            }
                        }
                    }).execute(Settings.getServer(), Settings.getUser(), Settings.getPassword(),
                            AsyncFtpClient.ACTION.DOWNLOAD,
                            localDir + "/" + Settings.getManagementInfo(),
                            Settings.getSettingList().get("path") +
                                    "/" + Settings.getManagementInfo());

                }
            } catch (Exception e) {
                Log.d(Settings.context.getString(R.string.tag), "download file failed");
            }
        }

        // load user setting
        try {
            readUserInfoFile(context.getFilesDir());
        } catch (Exception ioe) {

            try {

                if (Settings.getServerMode().equalsIgnoreCase("http")) {
                    new AsyncHttpClient(
                            context
                            ,Settings.getServer() + "/" + Settings.getPath() + "/" + Settings.getUserInfo()
                            , ""
                    ) {
                        @Override
                        public void onFinished(String response, int resp_code) {
                            Log.d(Settings.context.getString(R.string.tag), "response: " + response);
                            if (resp_code == 200) {
                                Log.d(Settings.context.getString(R.string.tag), "write user info file...");
                                try {
                                    (new FileUtil(context)).writeFile(USER_INFO, context.getFilesDir().getAbsolutePath(), response);
                                } catch (IOException ioe) {
                                    Log.d(Settings.context.getString(R.string.tag), "cannot write file, error:" + ioe.getMessage());
                                }
                            }
                        }
                    }
                            .execute();
                } else {
                    new AsyncFtpClient(new AsyncFtpClient.TaskListener() {
                        @Override
                        public void onFinished(String result) {
                            // Do Something after the task has finished
                            try {
                                Toast.makeText(context, "Config files updated. Restart required!",
                                        Toast.LENGTH_LONG).show();
                                readUserInfoFile(context.getFilesDir());


                            } catch (IOException e) {
                                Log.d(Settings.context.getString(R.string.tag), "read User info file error");
                            }
                        }
                    }).execute(Settings.getServer(), Settings.getUser(), Settings.getPassword(),
                            AsyncFtpClient.ACTION.DOWNLOAD,
                            localDir + "/" + Settings.getUserInfo(),
                            Settings.getSettingList().get("path") +
                                    "/" + Settings.getUserInfo());
                }

            } catch (Exception e) {
                Log.d(Settings.context.getString(R.string.tag), "download file failed");
            }
        }
    }

    public static Bitmap getBackground() {
        return background;
    }

    public static void setBackground(Bitmap background) {
        Settings.background = background;
    }

    public static UserInfo getUserInfoX() {
        return userInfoX;
    }

    public static void setUserInfoX(UserInfo userInfoX) {
        Settings.userInfoX = userInfoX;
    }

    public static Map<String, String> getMgmtList() {
        return mgmtList;
    }

    public static Map<String, String> getSettingList() {
        return settingList;
    }

    public static void setSettingList(Map<String, String> settingList) {
        Settings.settingList = settingList;
    }

    public static Map<String, String> getUsrList() {
        return usrList;
    }

    public static String getDeviceNo() {
        return Settings.settingList.get("device_no");
    }

    public static void setDeviceNo(String device_no) {
        Settings.settingList.put("device_no", device_no);
    }

    public static String getSettingPath() {
        return SETTING_PATH;
    }

    public static String getLogPath() {
        return LOG_PATH;
    }

    public static String getServerMode() {
        return Settings.settingList.get("server_mode");
    }

    public static void setServerMode(String server_mode) {
        Settings.settingList.put("server_mode", server_mode);
    }

    public static String getServer() {
        return Settings.settingList.get("server");
    }

    public static void setServer(String server) {
        Settings.settingList.put("server", server);
    }

    public static String getUser() {
        return Settings.settingList.get("user");
    }

    public static void setUser(String user) {
        Settings.settingList.put("user", user);
    }

    public static String getPassword() {
        return Settings.settingList.get("password");
    }

    public static void setPassword(String password) {
        Settings.settingList.put("password", password);
    }

    public static String getPath() {
        return Settings.settingList.get("path");
    }

    public static void setPath(String path) {
        Settings.settingList.put("path", path);
    }

    public static String getManagementInfo() {
        return MANAGEMENT_INFO;
    }

    public static String getSettingInfo() {
        return SETTING_INFO;
    }

    public static String getUserInfo() {
        return USER_INFO;
    }

    public static String getStateInfo() {
        return STATE_INFO;
    }

    public static String getJobInfo() {
        return JOB_INFO;
    }

    public static void removeAllFile(File dir) {
        String[] filename_ = {
                Settings.getUserInfo(),
                Settings.getManagementInfo(),
                Settings.getSettingInfo(),
                Settings.getMgmtList().get("background-file")
        };
        for (String filename : filename_) {
            File file = new File(dir, filename);
            if (file.exists()) {
                if (file.delete()) {
                    Log.i(Settings.context.getString(R.string.tag), "file removed :" + filename);
                } else {
                    Log.i(Settings.context.getString(R.string.tag), "remove failed :" + filename);
                }
            }
        }
    }

    public static void removeAllFileExceptSettings(File dir) {
        String[] filename_ = {
                Settings.getUserInfo(),
                Settings.getManagementInfo(),
                Settings.getMgmtList().get("background-file")
        };
        for (String filename : filename_) {
            File file = new File(dir, filename);
            if (file.exists()) {
                if (file.delete()) {
                    Log.i(Settings.context.getString(R.string.tag), "file removed :" + filename);
                } else {
                    Log.i(Settings.context.getString(R.string.tag), "remove failed :" + filename);
                }
            }
        }
    }
}
