package com.example.sleeptracker;

import android.os.Handler;
import android.os.Looper;

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

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SleepApi {

    private static final String API_URL = "https://stvfu.com/page/web_app/sleep/api_action.php";

    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    private final Handler mainHandler = new Handler(Looper.getMainLooper());

    private String username;
    private String password;

    public void setCredentials(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public interface StatusCallback {
        void onResult(String action, String actionKey, String recordedAt);
        void onError(String error, boolean authFailed);
    }

    public interface CheckinCallback {
        void onResult(int id, String recordedAt, String action);
        void onError(String error, boolean authFailed);
    }

    public interface HistoryCallback {
        void onResult(JSONArray records);
        void onError(String error, boolean authFailed);
    }

    private JSONObject post(JSONObject body) throws ApiException {
        try {
            body.put("username", username);
            body.put("password", password);

            URL url = new URL(API_URL);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
            conn.setDoOutput(true);
            conn.setConnectTimeout(10000);
            conn.setReadTimeout(10000);

            try (OutputStream os = conn.getOutputStream()) {
                os.write(body.toString().getBytes("UTF-8"));
            }

            int code = conn.getResponseCode();
            InputStream is = (code >= 200 && code < 300) ? conn.getInputStream() : conn.getErrorStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            reader.close();
            conn.disconnect();

            if (code == 401) {
                throw new ApiException("帳號或密碼錯誤", true);
            }
            if (code >= 400) {
                throw new ApiException("HTTP " + code, false);
            }

            return new JSONObject(sb.toString());
        } catch (ApiException e) {
            throw e;
        } catch (Exception e) {
            throw new ApiException(e.getMessage(), false);
        }
    }

    public void getStatus(StatusCallback callback) {
        executor.execute(() -> {
            try {
                JSONObject body = new JSONObject();
                body.put("action", "status");
                JSONObject result = post(body);
                String action = result.isNull("action") ? null : result.getString("action");
                String actionKey = result.isNull("action_key") ? null : result.optString("action_key", null);
                String recordedAt = result.isNull("recorded_at") ? null : result.getString("recorded_at");
                mainHandler.post(() -> callback.onResult(action, actionKey, recordedAt));
            } catch (ApiException e) {
                mainHandler.post(() -> callback.onError(e.getMessage(), e.isAuthFailed()));
            } catch (Exception e) {
                mainHandler.post(() -> callback.onError(e.getMessage(), false));
            }
        });
    }

    public void checkin(String type, CheckinCallback callback) {
        executor.execute(() -> {
            try {
                JSONObject body = new JSONObject();
                body.put("action", "checkin");
                body.put("type", type);
                JSONObject result = post(body);
                int id = result.getInt("id");
                String recordedAt = result.getString("recorded_at");
                String action = result.getString("action");
                mainHandler.post(() -> callback.onResult(id, recordedAt, action));
            } catch (ApiException e) {
                mainHandler.post(() -> callback.onError(e.getMessage(), e.isAuthFailed()));
            } catch (Exception e) {
                mainHandler.post(() -> callback.onError(e.getMessage(), false));
            }
        });
    }

    public void getHistory(int limit, HistoryCallback callback) {
        executor.execute(() -> {
            try {
                JSONObject body = new JSONObject();
                body.put("action", "history");
                body.put("limit", limit);
                JSONObject result = post(body);
                JSONArray records = result.getJSONArray("records");
                mainHandler.post(() -> callback.onResult(records));
            } catch (ApiException e) {
                mainHandler.post(() -> callback.onError(e.getMessage(), e.isAuthFailed()));
            } catch (Exception e) {
                mainHandler.post(() -> callback.onError(e.getMessage(), false));
            }
        });
    }

    static class ApiException extends Exception {
        private final boolean authFailed;

        ApiException(String message, boolean authFailed) {
            super(message);
            this.authFailed = authFailed;
        }

        boolean isAuthFailed() {
            return authFailed;
        }
    }
}
