package co.za.langalibalele.fuelmanagement;

import android.Manifest;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Base64;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.google.android.material.button.MaterialButton;
import com.google.android.material.textfield.TextInputEditText;
import com.google.gson.Gson;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;

import co.za.langalibalele.fuelmanagement.models.ApiResponse;
import co.za.langalibalele.fuelmanagement.utils.ApiClient;
import co.za.langalibalele.fuelmanagement.utils.SessionManager;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

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

public class DailyDefectsActivity extends AppCompatActivity {

    private static final int PERMISSION_REQUEST_CODE = 200;
    
    private SessionManager sessionManager;
    private TextView driverNameText, recordingStatus;
    private TextInputEditText dateInput, timeInput, dcInput, coyInput, defectDescriptionInput, remarksInput;
    private AutoCompleteTextView busNoSpinner, defectCategorySpinner;
    private MaterialButton recordButton, playButton, addPhotoButton, submitButton;
    private RecyclerView photosRecyclerView;
    private View progressBar;

    private Calendar calendar;
    private MediaRecorder mediaRecorder;
    private MediaPlayer mediaPlayer;
    private String audioFilePath = "";
    private boolean isRecording = false;
    private List<String> photosList = new ArrayList<>();
    private ActivityResultLauncher<Intent> cameraLauncher;
    private ActivityResultLauncher<Intent> galleryLauncher;

    private final String[] busNumbers = {
            "1001", "1002", "1003", "1004", "1006", "1007", "1008", "1012", "1013", "1014",
            "1015", "1010", "1011", "1016", "1018", "1020", "1201", "1202", "1203", "1204",
            "1205", "1206", "1207", "1208", "1209", "1210", "1211", "1221", "1222", "1300"
    };

    private final String[] defectCategories = {
            "Mechanical Issues",
            "Body Damage",
            "Interior Problems",
            "Safety Concerns",
            "Electrical Issues",
            "Tire/Wheel Issues",
            "Other"
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_daily_defects);

        sessionManager = new SessionManager(this);
        calendar = Calendar.getInstance();

        setupToolbar();
        initViews();
        setupUI();
        setupListeners();
        setupImagePickers();
        checkPermissions();
    }

    private void setupToolbar() {
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        if (getSupportActionBar() != null) {
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        }
    }

    private void initViews() {
        driverNameText = findViewById(R.id.driverNameText);
        dateInput = findViewById(R.id.dateInput);
        timeInput = findViewById(R.id.timeInput);
        busNoSpinner = findViewById(R.id.busNoSpinner);
        dcInput = findViewById(R.id.dcInput);
        coyInput = findViewById(R.id.coyInput);
        defectCategorySpinner = findViewById(R.id.defectCategorySpinner);
        defectDescriptionInput = findViewById(R.id.defectDescriptionInput);
        recordButton = findViewById(R.id.recordButton);
        playButton = findViewById(R.id.playButton);
        recordingStatus = findViewById(R.id.recordingStatus);
        addPhotoButton = findViewById(R.id.addPhotoButton);
        photosRecyclerView = findViewById(R.id.photosRecyclerView);
        remarksInput = findViewById(R.id.remarksInput);
        submitButton = findViewById(R.id.submitButton);
        progressBar = findViewById(R.id.progressBar);
    }

    private void setupUI() {
        driverNameText.setText(sessionManager.getDriverName());
        updateDateLabel();
        updateTimeLabel();

        ArrayAdapter<String> busAdapter = new ArrayAdapter<>(this,
                android.R.layout.simple_dropdown_item_1line, busNumbers);
        busNoSpinner.setAdapter(busAdapter);

        ArrayAdapter<String> categoryAdapter = new ArrayAdapter<>(this,
                android.R.layout.simple_dropdown_item_1line, defectCategories);
        defectCategorySpinner.setAdapter(categoryAdapter);

        photosRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
    }

    private void setupListeners() {
        dateInput.setOnClickListener(v -> showDatePicker());
        timeInput.setOnClickListener(v -> showTimePicker());
        recordButton.setOnClickListener(v -> toggleRecording());
        playButton.setOnClickListener(v -> playRecording());
        addPhotoButton.setOnClickListener(v -> showPhotoOptions());
        submitButton.setOnClickListener(v -> submitForm());
    }

    private void setupImagePickers() {
        cameraLauncher = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                result -> {
                    if (result.getResultCode() == RESULT_OK && result.getData() != null) {
                        Bundle extras = result.getData().getExtras();
                        Bitmap imageBitmap = (Bitmap) extras.get("data");
                        handleImage(imageBitmap);
                    }
                });

        galleryLauncher = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                result -> {
                    if (result.getResultCode() == RESULT_OK && result.getData() != null) {
                        Uri imageUri = result.getData().getData();
                        try {
                            Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), imageUri);
                            handleImage(bitmap);
                        } catch (IOException e) {
                            Toast.makeText(this, "Failed to load image", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
    }

    private void checkPermissions() {
        String[] permissions = {
                Manifest.permission.RECORD_AUDIO,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE
        };

        List<String> permissionsNeeded = new ArrayList<>();
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                permissionsNeeded.add(permission);
            }
        }

        if (!permissionsNeeded.isEmpty()) {
            ActivityCompat.requestPermissions(this,
                    permissionsNeeded.toArray(new String[0]),
                    PERMISSION_REQUEST_CODE);
        }
    }

    private void showDatePicker() {
        DatePickerDialog datePickerDialog = new DatePickerDialog(
                this,
                (view, year, month, dayOfMonth) -> {
                    calendar.set(Calendar.YEAR, year);
                    calendar.set(Calendar.MONTH, month);
                    calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
                    updateDateLabel();
                },
                calendar.get(Calendar.YEAR),
                calendar.get(Calendar.MONTH),
                calendar.get(Calendar.DAY_OF_MONTH)
        );
        datePickerDialog.show();
    }

    private void showTimePicker() {
        TimePickerDialog timePickerDialog = new TimePickerDialog(
                this,
                (view, hourOfDay, minute) -> {
                    calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
                    calendar.set(Calendar.MINUTE, minute);
                    updateTimeLabel();
                },
                calendar.get(Calendar.HOUR_OF_DAY),
                calendar.get(Calendar.MINUTE),
                true
        );
        timePickerDialog.show();
    }

    private void updateDateLabel() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
        dateInput.setText(sdf.format(calendar.getTime()));
    }

    private void updateTimeLabel() {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm", Locale.getDefault());
        timeInput.setText(sdf.format(calendar.getTime()));
    }

    private void toggleRecording() {
        if (isRecording) {
            stopRecording();
        } else {
            startRecording();
        }
    }

    private void startRecording() {
        try {
            audioFilePath = getExternalCacheDir().getAbsolutePath() + "/defect_audio_" + System.currentTimeMillis() + ".3gp";
            
            mediaRecorder = new MediaRecorder();
            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
            mediaRecorder.setOutputFile(audioFilePath);
            mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            mediaRecorder.prepare();
            mediaRecorder.start();

            isRecording = true;
            recordButton.setText("Stop Recording");
            recordButton.setBackgroundTintList(getColorStateList(R.color.error));
            recordingStatus.setText("Recording...");
            recordingStatus.setVisibility(View.VISIBLE);
            playButton.setEnabled(false);

        } catch (Exception e) {
            Toast.makeText(this, "Recording failed: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    private void stopRecording() {
        try {
            if (mediaRecorder != null) {
                mediaRecorder.stop();
                mediaRecorder.release();
                mediaRecorder = null;
            }

            isRecording = false;
            recordButton.setText("Record");
            recordButton.setBackgroundTintList(getColorStateList(R.color.primary));
            recordingStatus.setText("Recording saved");
            playButton.setEnabled(true);

        } catch (Exception e) {
            Toast.makeText(this, "Stop recording failed: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    private void playRecording() {
        if (audioFilePath.isEmpty()) {
            Toast.makeText(this, "No recording available", Toast.LENGTH_SHORT).show();
            return;
        }

        try {
            if (mediaPlayer != null) {
                mediaPlayer.release();
            }

            mediaPlayer = new MediaPlayer();
            mediaPlayer.setDataSource(audioFilePath);
            mediaPlayer.prepare();
            mediaPlayer.start();

            mediaPlayer.setOnCompletionListener(mp -> {
                playButton.setText("Play");
            });

            playButton.setText("Playing...");

        } catch (Exception e) {
            Toast.makeText(this, "Playback failed: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    private void showPhotoOptions() {
        String[] options = {"Camera", "Gallery", "Cancel"};
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Add Photo");
        builder.setItems(options, (dialog, which) -> {
            if (which == 0) {
                openCamera();
            } else if (which == 1) {
                openGallery();
            }
        });
        builder.show();
    }

    private void openCamera() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        cameraLauncher.launch(takePictureIntent);
    }

    private void openGallery() {
        Intent pickPhotoIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        galleryLauncher.launch(pickPhotoIntent);
    }

    private void handleImage(Bitmap bitmap) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos);
        byte[] imageBytes = baos.toByteArray();
        String photoBase64 = Base64.encodeToString(imageBytes, Base64.DEFAULT);
        
        photosList.add(photoBase64);
        photosRecyclerView.setVisibility(View.VISIBLE);
        Toast.makeText(this, "Photo added (" + photosList.size() + ")", Toast.LENGTH_SHORT).show();
    }

    private void submitForm() {
        if (dateInput.getText().toString().isEmpty()) {
            Toast.makeText(this, "Please select a date", Toast.LENGTH_SHORT).show();
            return;
        }
        if (busNoSpinner.getText().toString().isEmpty()) {
            Toast.makeText(this, "Please select bus number", Toast.LENGTH_SHORT).show();
            return;
        }
        if (defectCategorySpinner.getText().toString().isEmpty()) {
            Toast.makeText(this, "Please select defect category", Toast.LENGTH_SHORT).show();
            return;
        }

        setLoading(true);

        try {
            JSONObject jsonData = new JSONObject();
            jsonData.put("driver_name", sessionManager.getDriverName());
            jsonData.put("date", dateInput.getText().toString());
            jsonData.put("time", timeInput.getText().toString());
            jsonData.put("bus_no", busNoSpinner.getText().toString());
            jsonData.put("dc", dcInput.getText().toString());
            jsonData.put("coy", coyInput.getText().toString());
            jsonData.put("defect_category", defectCategorySpinner.getText().toString());
            jsonData.put("defect_description", defectDescriptionInput.getText().toString());
            jsonData.put("remarks", remarksInput.getText().toString());

            // Add voice recording
            String voiceBase64 = "";
            if (!audioFilePath.isEmpty()) {
                File audioFile = new File(audioFilePath);
                byte[] audioBytes = new byte[(int) audioFile.length()];
                FileInputStream fis = new FileInputStream(audioFile);
                fis.read(audioBytes);
                fis.close();
                voiceBase64 = Base64.encodeToString(audioBytes, Base64.DEFAULT);
            }
            jsonData.put("voice_recording", voiceBase64);

            // Add photos
            JSONArray photosArray = new JSONArray();
            for (String photo : photosList) {
                photosArray.put(photo);
            }
            jsonData.put("photos", photosArray);

            OkHttpClient client = ApiClient.getClient();
            RequestBody body = RequestBody.create(
                    jsonData.toString(),
                    MediaType.parse("application/json; charset=utf-8")
            );

            Request request = new Request.Builder()
                    .url(ApiClient.getBaseUrl() + "save_defect_entry.php")
                    .post(body)
                    .build();

            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    runOnUiThread(() -> {
                        setLoading(false);
                        Toast.makeText(DailyDefectsActivity.this,
                                "Connection failed: " + e.getMessage(), Toast.LENGTH_SHORT).show();
                    });
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    String responseBody = response.body().string();

                    runOnUiThread(() -> {
                        setLoading(false);
                        try {
                            Gson gson = new Gson();
                            ApiResponse apiResponse = gson.fromJson(responseBody, ApiResponse.class);

                            if (apiResponse.isSuccess()) {
                                Toast.makeText(DailyDefectsActivity.this,
                                        "Defect entry saved successfully!", Toast.LENGTH_SHORT).show();
                                clearForm();
                            } else {
                                Toast.makeText(DailyDefectsActivity.this,
                                        "Error: " + apiResponse.getMessage(), Toast.LENGTH_SHORT).show();
                            }
                        } catch (Exception e) {
                            Toast.makeText(DailyDefectsActivity.this,
                                    "Invalid response from server", Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            });

        } catch (Exception e) {
            setLoading(false);
            Toast.makeText(this, "Error preparing data: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    private void clearForm() {
        busNoSpinner.setText("");
        dcInput.setText("");
        coyInput.setText("");
        defectCategorySpinner.setText("");
        defectDescriptionInput.setText("");
        remarksInput.setText("");
        audioFilePath = "";
        photosList.clear();
        photosRecyclerView.setVisibility(View.GONE);
        recordingStatus.setVisibility(View.GONE);
        playButton.setEnabled(false);
        updateDateLabel();
        updateTimeLabel();
    }

    private void setLoading(boolean loading) {
        progressBar.setVisibility(loading ? View.VISIBLE : View.GONE);
        submitButton.setEnabled(!loading);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mediaRecorder != null) {
            mediaRecorder.release();
            mediaRecorder = null;
        }
        if (mediaPlayer != null) {
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {
            finish();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}
