package ErhaAPI;

import Config.SomeCodes;
import com.google.gson.Gson;
import lombok.Getter;
import org.tinylog.Logger;


import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.util.Base64;
import java.util.UUID;

import static Config.SomeCodes.*;


public class ErhaAPI {
    private @Getter String API_USERNAME = "erha-pb-001";
    private @Getter String API_PASSWORD = "bM0tH!s";



    private String auth;
    private final String API_URL;

    private final Gson gson = new Gson();

    /**
     * Create Erha API object
     * @param isProduction if true will use Production URL, if false will use Staging URL
     */
    public ErhaAPI(boolean isProduction){
        final String API_URL_PROD = "https://connect-api.aryanoble.co.id/api";
        final String API_URL_STAGING = "https://connect-api-staging.aryanoble.web.id/api";
        API_URL = isProduction ? API_URL_PROD : API_URL_STAGING;
        update_auth();
    }
    /**
     * Set API Username
     * @param API_USERNAME API Username
     */
    @SuppressWarnings("unused")
    public void setAPI_USERNAME(String API_USERNAME){
        if (ValidString(API_USERNAME)){
            if (!API_USERNAME.equals(this.API_USERNAME)){
                this.API_USERNAME = API_USERNAME;
                update_auth();
            }
        }
    }

    /**
     * Set API Password
     * @param API_PASSWORD API Password
     */
    @SuppressWarnings("unused")
    public void setAPI_PASSWORD(String API_PASSWORD){
        if (ValidString(API_PASSWORD)){
            if (!API_PASSWORD.equals(this.API_PASSWORD)){
                this.API_PASSWORD = API_PASSWORD;
                update_auth();
            }
        }
    }

    /**
     * Validate Barcode data
     * @param Barcode Barcode to verify
     * @return BarcodeResullt object if success, or null if failed
     */
    public BarcodeResullt Validate_Barcode(String Barcode, boolean printdebug){
        if (ValidBarCode(Barcode)){

            try (HttpClient client = HttpClient.newHttpClient()) {
                int medical_record_detail_id = toInt(Barcode);
                HttpRequest request = HttpRequest.newBuilder()
                        .uri(java.net.URI.create(API_URL+"/photobooth/photobooth/" + medical_record_detail_id))
                        .header("Authorization", "Basic " + auth)
                        .GET()
                        .build();
                HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
                if (response.statusCode()==200){
                    String body = response.body();
                    if (printdebug){
                        System.out.println("Validate_Barcode status code : " + response.statusCode());
                        System.out.println("Validate_Barcode HTTP body : ");
                        System.out.println(body);
                    }
                    return gson.fromJson(body, BarcodeResullt.class);
                } else {
                    Logger.error("Validate_Barcode failed, status code : " , response.statusCode());
                    System.out.println("Validate Barcode status code : " + response.statusCode());
                }

            } catch (IOException e) {
                System.out.println("Validate_Barcode IO Exception, Msg : " + e.getMessage());
                Logger.error("Validate_Barcode IO Exception, Msg : " , e.getMessage());
            } catch (InterruptedException e) {
                System.out.println("Validate_Barcode Interrupted Exception, Msg : " + e.getMessage());
                Logger.error("Validate_Barcode Interrupted Exception, Msg : " , e.getMessage());
            }

        }
        return null;
    }




    /**
     * Upload File
     * @param patientID Patient ID
     * @param filename File to upload
     * @return null if failed, or response body if success
     */
    public UploadResult Upload_File(String patientID, String filename, boolean printdebug)  {
        if (ValidMedicalRecordId(patientID)){
            int medical_record_detail_id = toInt(patientID);
            if (ValidFile(filename)){
                File ff = new File(filename);
                try (HttpClient client = HttpClient.newHttpClient()){
                    byte[] fileBytes = Files.readAllBytes(new java.io.File(filename).toPath());
                    String fn = ff.getName();
                    // Unique boundary for multipart data
                    String boundary = "----JavaHttpClientBoundary" + UUID.randomUUID();
                    String CRLF = "\r\n";

                    // Form Data (Text Field)
                    String formData1 = "--" + boundary + CRLF +
                            "Content-Disposition: form-data; name=\"medical_record_detail_id\"" + CRLF + CRLF +
                            medical_record_detail_id + CRLF;

                    // Form Data (File)
                    String formData2 = "--" + boundary + CRLF +
                            "Content-Disposition: form-data; name=\"file\"; filename=\"" + fn + "\"" + CRLF +
                            "Content-Type: image/jpeg" + CRLF + CRLF; // Change Content-Type accordingly

                    // End Boundary
                    String endBoundary = CRLF + "--" + boundary + "--" + CRLF;

                    // Combine all parts into a single byte array
                    byte[] multipartData = SomeCodes.Concat(
                            formData1.getBytes(),
                            formData2.getBytes(),
                            fileBytes,
                            endBoundary.getBytes()
                    );


                    HttpRequest request = HttpRequest.newBuilder()
                            .uri(new URI(API_URL + "/photobooth/photobooth"))
                            .header("Authorization", "Basic " + auth)
                            .header("Content-Type", "multipart/form-data; boundary=" + boundary)
                            .POST(HttpRequest.BodyPublishers.ofByteArray(multipartData))
                            .build();

                    // Send request
                    HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

                    if (printdebug){
                        System.out.println("Upload_File status code : " + response.statusCode());
                        System.out.println("Upload_File HTTP body : ");
                        System.out.println(response.body());
                    }


                    if (response.statusCode()==200){
                        return gson.fromJson(response.body(), UploadResult.class);

                    } else {
                        System.out.println("Upload_File status code : " + response.statusCode());
                        Logger.error("Upload_File file ",filename," failed, status code : " , response.statusCode());
                    }


                } catch (Exception e){
                    System.out.println("Upload_File Exception, Msg : " + e.getMessage());
                    Logger.error("Upload_File file ",filename," failed, Exception, Msg : " , e.getMessage());
                }
            }
        }
        return null;
    }


    private void update_auth(){
        auth = Base64.getEncoder().encodeToString((API_USERNAME + ":" + API_PASSWORD).getBytes());
    }

}
