<script setup lang="ts">
import DesignerCanvas from "~/components/designer/DesignerCanvas.vue";
import DesignerPreview from "~/components/designer/DesignerPreview.vue";
import DesignerToolbar from "~/components/designer/DesignerToolbar.vue";
import TemplatePicker from "~/components/designer/TemplatePicker.vue";

import { useSlipmatDesigner } from "~/composables/useSlipmatDesigner";
import type { ExportedDesign } from "~/composables/useSlipmatDesigner";

const {
  templates,
  selectedTemplate,
  selectTemplate,
  loadDesign,
  displaySize,
  templateLabel,
  productionPixelSize,
  previewUrl,
  registerCanvas,
  unregisterCanvas,
  setActiveCanvas,
  addTextbox,
  addShape,
  addImageFromFile,
  clearDesign,
  downloadPreview,
  downloadProduction,
  exportDesign,
  isExporting,
  activeFillColor,
  activeStrokeColor,
  canStyleSelection,
  setActiveFillColor,
  setActiveStrokeColor,
  setBackgroundColor,
  zoomLevel,
  minZoom,
  maxZoom,
  setZoom,
  zoomIn,
  zoomOut,
  resetZoom,
} = useSlipmatDesigner();

// Active view selector for multi-canvas design
const activeView = ref<'front' | 'top' | 'left' | 'right'>('front');

const setActiveView = (view: 'front' | 'top' | 'left' | 'right') => {
  activeView.value = view;
  setActiveCanvas(view);
};

const DESIGN_PRICE_USD = 39.99;

const { user, backendUser, initAuth, isLoading } = useAuth();
const loginModal = useLoginModal();
const route = useRoute();
const router = useRouter();
const config = useRuntimeConfig();

const activeDesignId = ref<string | null>(
  typeof route.query.designId === "string" ? route.query.designId : null
);
const loadedDesignId = ref<string | null>(null);
const isDesignLoading = ref(false);
const isCheckoutPending = ref(false);
const checkoutError = ref<string | null>(null);
const lastExportedDesign = ref<ExportedDesign | null>(null);

type LoadDesignInput = Parameters<typeof loadDesign>[0];

type StorageUploadResponse = {
  bucket: string;
  objectName: string;
  publicUrl: string;
  presignedUrl?: string | null;
  presignedUrlExpiresIn?: number | null;
};

const uploadDesignAsset = async (
  file: Blob,
  filename: string,
  options?: { prefix?: string; bucket?: string }
): Promise<StorageUploadResponse> => {
  if (!process.client) {
    throw new Error("Asset uploads can only run in the browser context.");
  }

  const backendUrl = config.public.backendUrl;
  if (!backendUrl) {
    throw new Error("Backend URL is not configured.");
  }

  const formData = new FormData();
  formData.append("file", file, filename);
  if (options?.prefix) {
    formData.append("prefix", options.prefix);
  }
  if (options?.bucket) {
    formData.append("bucket", options.bucket);
  }

  return await $fetch<StorageUploadResponse>("/storage/upload", {
    baseURL: backendUrl,
    method: "POST",
    body: formData,
  });
};

const persistDesign = async (designId: string, design: ExportedDesign) => {
  const safeDesignIdBase = designId.replace(/[^a-zA-Z0-9_-]/g, "-") || "design";
  const assetBasePath = `designs/${safeDesignIdBase}`;
  const timestamp = Date.now();

  if (!design.previewBlob || !design.productionBlob) {
    throw new Error("Design assets are missing; please export again.");
  }

  const canvasJsonString =
    typeof design.canvasJson === "string"
      ? design.canvasJson
      : JSON.stringify(design.canvasJson);

  const prefix = `${assetBasePath}/`;

  const [previewUpload, productionUpload, canvasUpload] = await Promise.all([
    uploadDesignAsset(design.previewBlob, `preview-${timestamp}.png`, {
      prefix,
    }),
    uploadDesignAsset(design.productionBlob, `production-${timestamp}.png`, {
      prefix,
    }),
    uploadDesignAsset(
      new Blob([canvasJsonString], { type: "application/json" }),
      `canvas-${timestamp}.json`,
      { prefix }
    ),
  ]);

  // Get Firebase ID token for authentication
  const idToken = user.value ? await user.value.getIdToken() : null;

  await $fetch("/api/designs", {
    method: "POST",
    headers: idToken ? { Authorization: `Bearer ${idToken}` } : {},
    body: {
      designId,
      templateId: design.templateId,
      ownerEmail: user.value?.email ?? null,
  ownerId: backendUser.value?.id ?? null,
      previewUrl: previewUpload.publicUrl,
      productionUrl: productionUpload.publicUrl,
      canvasJson: canvasUpload.publicUrl,
      metadata: {
        designName: templateLabel.value,
        storage: {
          preview: {
            objectName: previewUpload.objectName,
            bucket: previewUpload.bucket,
          },
          production: {
            objectName: productionUpload.objectName,
            bucket: productionUpload.bucket,
          },
          canvas: {
            objectName: canvasUpload.objectName,
            bucket: canvasUpload.bucket,
          },
        },
        storagePaths: {
          preview: previewUpload.objectName,
          production: productionUpload.objectName,
          canvas: canvasUpload.objectName,
        },
      },
    },
  });

  return {
    previewUrl: previewUpload.publicUrl,
    productionUrl: productionUpload.publicUrl,
    canvasJsonUrl: canvasUpload.publicUrl,
  };
};

const loadDesignById = async (designId: string) => {
  if (!process.client) {
    return;
  }

  isDesignLoading.value = true;
  try {
    const design = await $fetch<{
      designId?: string;
      templateId?: string | null;
      previewUrl?: string | null;
      productionUrl?: string | null;
      canvasJson?: unknown;
    }>(`/api/designs/${designId}`);

    if (!design?.canvasJson) {
      throw new Error("Saved design is missing canvas data.");
    }

    let canvasPayload: LoadDesignInput["canvasJson"] =
      design.canvasJson as LoadDesignInput["canvasJson"];

    if (typeof design.canvasJson === "string") {
      const trimmed = design.canvasJson.trim();
      const isRemoteSource = /^https?:\/\//i.test(trimmed);

      if (isRemoteSource) {
        const response = await fetch(trimmed);
        if (!response.ok) {
          throw new Error("Failed to download saved canvas data.");
        }
        canvasPayload =
          (await response.text()) as LoadDesignInput["canvasJson"];
      } else {
        canvasPayload = trimmed as LoadDesignInput["canvasJson"];
      }
    }

    await loadDesign({
      templateId: design.templateId ?? null,
      canvasJson: canvasPayload,
      previewUrl: design.previewUrl ?? null,
    });

    loadedDesignId.value = designId;
    lastExportedDesign.value = null;
  } catch (error: any) {
    console.error("Failed to load saved design", error);
  } finally {
    isDesignLoading.value = false;
  }
};

watch(
  () => route.query.designId,
  (value) => {
    const nextId = typeof value === "string" ? value : null;
    if (nextId !== activeDesignId.value) {
      activeDesignId.value = nextId;
    }
  }
);

watch(
  activeDesignId,
  (designId) => {
    if (!designId || designId === loadedDesignId.value) {
      return;
    }
    loadDesignById(designId);
  },
  { immediate: true }
);

onMounted(() => {
  initAuth();
});

const handleTemplateSelect = (templateId: string) => {
  selectTemplate(templateId);
};

const handleExport = async () => {
  const result = await exportDesign();
  if (result) {
    lastExportedDesign.value = result;
  }
};

const handleCheckout = async () => {
  if (!process.client) {
    return;
  }

  initAuth();

  if (isLoading.value) {
    for (
      let attempt = 0;
      attempt < 10 && isLoading.value && !user.value;
      attempt += 1
    ) {
      await new Promise((resolve) => setTimeout(resolve, 50));
    }
  }

  if (!user.value) {
    loginModal.value = true;
    return;
  }

  checkoutError.value = null;
  isCheckoutPending.value = true;

  try {
    let exportResult = await exportDesign();
    if (!exportResult) {
      exportResult = lastExportedDesign.value;
    }
    if (!exportResult) {
      throw new Error("Unable to export the current design. Please try again.");
    }
    lastExportedDesign.value = exportResult;

    const designId =
      activeDesignId.value ??
      (typeof crypto !== "undefined" && "randomUUID" in crypto
        ? crypto.randomUUID()
        : `design-${Date.now()}`);

    await persistDesign(designId, exportResult);

    activeDesignId.value = designId;
    loadedDesignId.value = designId;

    if (
      typeof route.query.designId !== "string" ||
      route.query.designId !== designId
    ) {
      await router.replace({ query: { designId } });
    }

    const successUrlTemplate = `${window.location.origin}/checkout/success?session_id={CHECKOUT_SESSION_ID}`;
    const cancelUrl = window.location.href;

    const session = await $fetch<{ id: string; url?: string | null }>(
      "/api/checkout.session",
      {
        method: "POST",
        body: {
          designId,
          templateId: exportResult.templateId,
          designName: templateLabel.value,
          amount: DESIGN_PRICE_USD,
          currency: "usd",
          successUrl: successUrlTemplate,
          cancelUrl,
          customerEmail: user.value?.email ?? undefined,
        },
      }
    );

    if (!session?.id) {
      throw new Error("Stripe session could not be created.");
    }

    if (session.url) {
      window.location.href = session.url;
      return;
    }

    const fallbackRedirect = successUrlTemplate.replace(
      "{CHECKOUT_SESSION_ID}",
      session.id
    );
    window.location.href = fallbackRedirect;
  } catch (err: any) {
    console.error("Checkout failed", err);
    checkoutError.value =
      err?.message ?? "Unable to start checkout. Please try again.";
  } finally {
    isCheckoutPending.value = false;
  }
};
</script>

<template>
  <main class="min-h-screen bg-white pb-16 text-slate-900">
    <AppNavbar />
    <div class="mx-auto max-w-6xl px-4 pt-12 sm:px-6 lg:px-8">
      <header class="space-y-3">
        <p class="text-sm uppercase tracking-[0.35em] text-slate-600">
          TableJerseys Designer
        </p>
        <h1 class="text-3xl font-bold text-slate-900 sm:text-4xl">
          Craft custom jerseys ready for your table.
        </h1>
      </header>

      <section class="mt-10 flex flex-col gap-8 lg:grid lg:grid-cols-[320px_minmax(0,1fr)] lg:gap-6">
        <!-- Left Sidebar - Template Picker and Preview (together on desktop, separate on mobile) -->
        <div class="contents lg:block lg:space-y-6">
          <!-- <div class="order-1">
            <TemplatePicker
              :templates="templates"
              :selected-template-id="selectedTemplate.id"
              @select="handleTemplateSelect"
            />
          </div> -->

          <div class="order-3">
            <DesignerPreview
              :is-checkout-pending="isCheckoutPending"
              :checkout-price="DESIGN_PRICE_USD"
              :checkout-error="checkoutError"
              @checkout="handleCheckout"
            />
          </div>
        </div>

        <!-- Designer Canvas - Second on mobile, right column on desktop -->
        <div class="order-2 flex flex-col gap-6 lg:order-0">
          <!-- View Selector Tabs -->
          <div class="flex gap-2 rounded-lg border border-slate-200 bg-slate-50 p-2">
            <button
              v-for="view in ['front', 'top', 'left', 'right']"
              :key="view"
              @click="setActiveView(view as 'front' | 'top' | 'left' | 'right')"
              :class="[
                'flex-1 rounded-md px-4 py-2 text-sm font-semibold capitalize transition-all',
                activeView === view
                  ? 'bg-white text-slate-900 shadow-sm'
                  : 'text-slate-600 hover:text-slate-900'
              ]"
            >
              {{ view }} View
            </button>
          </div>

          <div
            class="rounded-3xl border border-slate-200 bg-white shadow-xl"
          >
            <DesignerToolbar
              :on-add-text="addTextbox"
              :on-add-circle="() => addShape('circle')"
              :on-add-rectangle="() => addShape('rect')"
              :on-clear="clearDesign"
              :on-import-image="addImageFromFile"
              :on-fill-change="setActiveFillColor"
              :on-stroke-change="setActiveStrokeColor"
              :on-background-change="setBackgroundColor"
              :active-fill="activeFillColor"
              :active-stroke="activeStrokeColor"
              :active-background="selectedTemplate.backgroundColor"
              :can-style-selection="canStyleSelection"
              :zoom="zoomLevel"
              :min-zoom="minZoom"
              :max-zoom="maxZoom"
              :on-zoom-change="setZoom"
              :on-zoom-in="zoomIn"
              :on-zoom-out="zoomOut"
              :on-zoom-reset="resetZoom"
            />
            <div class="p-6 space-y-4">
              <!-- Canvas for each view -->
              <div v-show="activeView === 'front'" class="canvas-container">
                <h3 class="mb-2 text-sm font-semibold text-slate-700">Front View</h3>
                <DesignerCanvas
                  canvas-id="front"
                  :size="displaySize"
                  :background-color="selectedTemplate.backgroundColor"
                  :register-canvas="registerCanvas"
                  :unregister-canvas="unregisterCanvas"
                />
              </div>
              
              <div v-show="activeView === 'top'" class="canvas-container">
                <h3 class="mb-2 text-sm font-semibold text-slate-700">Top View</h3>
                <DesignerCanvas
                  canvas-id="top"
                  :size="displaySize"
                  :background-color="selectedTemplate.backgroundColor"
                  :register-canvas="registerCanvas"
                  :unregister-canvas="unregisterCanvas"
                />
              </div>
              
              <div v-show="activeView === 'left'" class="canvas-container">
                <h3 class="mb-2 text-sm font-semibold text-slate-700">Left View</h3>
                <DesignerCanvas
                  canvas-id="left"
                  :size="displaySize"
                  :background-color="selectedTemplate.backgroundColor"
                  :register-canvas="registerCanvas"
                  :unregister-canvas="unregisterCanvas"
                />
              </div>
              
              <div v-show="activeView === 'right'" class="canvas-container">
                <h3 class="mb-2 text-sm font-semibold text-slate-700">Right View</h3>
                <DesignerCanvas
                  canvas-id="right"
                  :size="displaySize"
                  :background-color="selectedTemplate.backgroundColor"
                  :register-canvas="registerCanvas"
                  :unregister-canvas="unregisterCanvas"
                />
              </div>

              <p class="mt-4 text-sm text-slate-600">
                Design each view of your table jersey separately. Switch between views using the tabs above. 
                Safe zone and bleed guides update automatically when you switch templates.
              </p>
            </div>
          </div>
        </div>
      </section>
    </div>
  </main>
</template>
