<template>
  <v-dialog v-model="showDialog" max-width="450" persistent>
    <v-card>
      <v-toolbar>
        <v-row no-gutters class="fill-height px-6" align="center">
          <span class="font-weight-bold text-h6">{{
            action === "checkIn" ? "Check In" : "Check Out"
          }}</span>
        </v-row>
      </v-toolbar>

      <v-card-text class="pa-4">
        <v-form ref="formRef" v-model="valid">
          <v-row no-gutters class="pa-0">
            <v-col cols="12" class="pa-0">
              <v-card
                variant="outlined"
                class="mb-2"
                style="height: 400px; position: relative; overflow: hidden"
              >
                <div
                  v-if="loadingCamera"
                  class="d-flex align-center justify-center"
                  style="height: 100%"
                >
                  <v-progress-circular
                    indeterminate
                    color="primary"
                    size="64"
                  />
                </div>

                <video
                  v-if="showCamera && !capturedImage"
                  ref="videoElement"
                  autoplay
                  playsinline
                  muted
                  style="
                    width: 100%;
                    height: 100%;
                    object-fit: cover;
                    display: block;
                    background: #000;
                  "
                />

                <img
                  v-else-if="capturedImage"
                  :src="capturedImage"
                  style="
                    width: 100%;
                    height: 100%;
                    object-fit: cover;
                    display: block;
                  "
                />

                <div
                  v-else-if="!loadingCamera"
                  class="d-flex align-center justify-center flex-column"
                  style="height: 100%; background: #f5f5f5"
                >
                  <v-icon size="64" color="grey" class="mb-2"
                    >mdi-camera-off</v-icon
                  >
                  <span class="text-caption text-grey"
                    >Initializing camera...</span
                  >
                </div>
              </v-card>
            </v-col>

            <v-col v-if="error" cols="12" class="pa-0 mt-2">
              <v-alert
                type="warning"
                variant="tonal"
                density="compact"
                closable
                @click:close="error = ''"
              >
                {{ error }}
              </v-alert>
            </v-col>
          </v-row>
        </v-form>
      </v-card-text>

      <v-toolbar class="pa-0" density="compact">
        <v-row no-gutters>
          <v-col v-if="!capturedImage" cols="6" class="pa-0">
            <v-btn
              block
              variant="text"
              class="text-none"
              size="large"
              @click="close"
              height="56"
            >
              Cancel
            </v-btn>
          </v-col>

          <v-col v-if="!capturedImage" cols="6" class="pa-0">
            <v-btn
              block
              variant="flat"
              color="black"
              class="text-none font-weight-bold rounded-0"
              height="56"
              size="large"
              @click="capturePhoto"
              :disabled="!showCamera"
            >
              <v-icon class="mr-2">mdi-camera</v-icon>
              Capture Photo
            </v-btn>
          </v-col>

          <template v-else>
            <v-col cols="6" class="pa-0">
              <v-btn
                block
                variant="text"
                class="text-none"
                size="large"
                @click="retakePhoto"
                height="56"
                :disabled="submitting"
              >
                <v-icon class="mr-2">mdi-camera-retake</v-icon>
                Retake
              </v-btn>
            </v-col>

            <v-col cols="6" class="pa-0">
              <v-btn
                block
                variant="flat"
                color="black"
                class="text-none font-weight-bold rounded-0"
                height="56"
                size="large"
                :loading="submitting"
                @click="submit"
              >
                <v-icon class="mr-2">mdi-check</v-icon>
                Submit
              </v-btn>
            </v-col>
          </template>
        </v-row>
      </v-toolbar>
    </v-card>
  </v-dialog>
</template>

<script setup lang="ts">
const showDialog = defineModel({ type: Boolean, default: false });

const emit = defineEmits(["saved", "close"]);

const props = defineProps({
  action: { type: String, default: "checkIn" }, // "checkIn" or "checkOut"
  serviceType: { type: String, default: "" },
});

const formRef = ref<any>(null);
const valid = ref(false);
const submitting = ref(false);
const error = ref("");
const loadingCamera = ref(false);

const imageFile = ref<File | null>(null);

const videoElement = ref<HTMLVideoElement | null>(null);
const showCamera = ref(false);
const capturedImage = ref<string | null>(null);
const mediaStream = ref<MediaStream | null>(null);

const { addFile } = useFile();

const openCamera = async () => {
  loadingCamera.value = true;
  error.value = "";

  try {
    if (mediaStream.value) {
      mediaStream.value.getTracks().forEach((track) => track.stop());
      mediaStream.value = null;
    }

    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
      throw new Error("Camera not supported in this browser");
    }

    const stream = await navigator.mediaDevices.getUserMedia({
      video: {
        facingMode: "user",
        width: { ideal: 1280 },
        height: { ideal: 720 },
      },
      audio: false,
    });

    mediaStream.value = stream;
    capturedImage.value = null;
    imageFile.value = null;
    showCamera.value = true;

    await nextTick();
    await nextTick();

    if (videoElement.value) {
      videoElement.value.srcObject = stream;

      videoElement.value.setAttribute("autoplay", "");
      videoElement.value.setAttribute("playsinline", "");
      videoElement.value.setAttribute("muted", "");

      try {
        await videoElement.value.play();
        console.log("Camera preview started successfully");
      } catch (playErr) {
        console.error("Error playing video:", playErr);
        throw playErr;
      }
    }
  } catch (err: any) {
    console.error("Camera error:", err);
    showCamera.value = false;

    if (
      err.name === "NotAllowedError" ||
      err.name === "PermissionDeniedError"
    ) {
      error.value =
        "Camera access denied. Please allow camera access in your browser settings.";
    } else if (
      err.name === "NotFoundError" ||
      err.name === "DevicesNotFoundError"
    ) {
      error.value = "No camera found on this device.";
    } else if (
      err.name === "NotReadableError" ||
      err.name === "TrackStartError"
    ) {
      error.value = "Camera is already in use by another application.";
    } else if (err.message === "Camera not supported in this browser") {
      error.value = err.message;
    } else {
      error.value =
        "Unable to access camera. Please check your browser permissions.";
    }
  } finally {
    loadingCamera.value = false;
  }
};

const capturePhoto = async () => {
  if (!videoElement.value) return;

  const canvas = document.createElement("canvas");
  canvas.width = videoElement.value.videoWidth;
  canvas.height = videoElement.value.videoHeight;
  const ctx = canvas.getContext("2d");

  if (!ctx) return;

  ctx.drawImage(videoElement.value, 0, 0);
  capturedImage.value = canvas.toDataURL("image/jpeg");

  const blob = await new Promise<Blob | null>((resolve) => {
    canvas.toBlob((blob) => resolve(blob), "image/jpeg");
  });

  if (!blob) return;

  const file = new File([blob], "captured-photo.jpg", {
    type: "image/jpeg",
  });

  stopCamera();

  try {
    submitting.value = true;
    const uploadRes = await addFile(file);
    imageFile.value = uploadRes?.id;
    error.value = "";
  } catch (err: any) {
    console.error("Error uploading file:", err);
    error.value =
      err.statusCode === 401
        ? "Authentication failed. Please refresh the page and try again."
        : "Failed to upload image. Please try again.";
  } finally {
    submitting.value = false;
  }
};

const retakePhoto = () => {
  capturedImage.value = null;
  imageFile.value = null;
  error.value = "";
  openCamera();
};

const stopCamera = () => {
  if (mediaStream.value) {
    mediaStream.value.getTracks().forEach((track) => track.stop());
    mediaStream.value = null;
  }
  showCamera.value = false;
};

const close = () => {
  stopCamera();
  resetForm();
  showDialog.value = false;
  emit("close");
};

const resetForm = () => {
  imageFile.value = null;
  capturedImage.value = null;
  showCamera.value = false;
  error.value = "";
  formRef.value?.resetValidation();
};

const getCurrentLocation = (): Promise<{
  latitude: number;
  longitude: number;
}> => {
  return new Promise((resolve, reject) => {
    if (!navigator.geolocation) {
      reject(new Error("Geolocation is not supported by your browser"));
      return;
    }

    navigator.geolocation.getCurrentPosition(
      (position) => {
        resolve({
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
        });
      },
      (err) => {
        reject(err);
      },
      {
        enableHighAccuracy: true,
        timeout: 10000,
        maximumAge: 0,
      }
    );
  });
};

const submit = async () => {
  if (!capturedImage.value) {
    error.value = "Please capture a photo before submitting";
    return;
  }

  submitting.value = true;
  error.value = "";

  try {
    const location = await getCurrentLocation();
    const imageId =
      typeof imageFile.value === "string" ? imageFile.value : undefined;

    const isoTimestamp = new Date().toISOString();

    const payload: any = {
      [props.action]: {
        timestamp: isoTimestamp,
        location: {
          latitude: location.latitude,
          longitude: location.longitude,
        },
      },
    };

    if (imageId) {
      payload[props.action].img = imageId;
    }

    if (props.serviceType) {
      payload.serviceType = props.serviceType;
    }

    emit("saved", payload);

    close();
  } catch (err: any) {
    console.error("Error submitting attendance:", err);

    if (err.message?.includes("Geolocation") || err.code) {
      error.value =
        "Unable to get your location. Please enable location services.";
    } else {
      error.value = "Failed to submit attendance. Please try again.";
    }
  } finally {
    submitting.value = false;
  }
};

watch(showDialog, async (newVal) => {
  if (newVal) {
    await nextTick();
    setTimeout(() => {
      openCamera();
    }, 100);
  } else {
    stopCamera();
  }
});
</script>
