import type { ActionFunctionArgs, LoaderFunctionArgs } from "react-router";
import {
  registerShop,
  getShopWithDecryptedToken,
  exchangeSessionTokenForAccessToken,
} from "../services/shop.server";
import {
  extractSessionTokenFromRequest,
  verifyShopifySessionToken,
} from "../shopify.server";
import { getDefaultStoreDomainSync } from "../services/platform-settings.server";
import prisma from "../db.server";

async function handleSessionTokenAuth(request: Request) {
  const sessionToken = extractSessionTokenFromRequest(request);
  if (!sessionToken) {
    return new Response(
      JSON.stringify({ authenticated: false, error: "Missing session token" }),
      {
        status: 401,
        headers: {
          "Content-Type": "application/json",
          "X-Shopify-Retry-Invalid-Session-Request": "1",
        },
      }
    );
  }

  const verified = verifyShopifySessionToken(sessionToken);
  if (!verified || !verified.shopDomain) {
    return new Response(
      JSON.stringify({ authenticated: false, error: "Invalid session token" }),
      {
        status: 401,
        headers: {
          "Content-Type": "application/json",
          "X-Shopify-Retry-Invalid-Session-Request": "1",
        },
      }
    );
  }

  const shopDomain = verified.shopDomain;
  const existing = await getShopWithDecryptedToken(shopDomain).catch(() => null);
  const currentTok = existing?.decryptedAccessToken || "";
  const isLegacyNonExpiring = Boolean(
    existing && (!existing.refreshToken || !existing.tokenExpiresAt)
  );
  const isExpired = Boolean(
    existing?.tokenExpiresAt && new Date(existing.tokenExpiresAt).getTime() <= Date.now()
  );
  let hasValidToken = Boolean(
    existing &&
      !existing.uninstalledAt &&
      currentTok &&
      currentTok !== "shpss_sample_token" &&
      !isLegacyNonExpiring &&
      !isExpired
  );

  if (!hasValidToken) {
    const exchanged = await exchangeSessionTokenForAccessToken(shopDomain, sessionToken);
    if (exchanged) {
      hasValidToken = true;
    }
  }

  return new Response(
    JSON.stringify({
      authenticated: true,
      shop: shopDomain,
      signatureVerified: verified.signatureVerified,
      hasValidToken,
    }),
    {
      status: 200,
      headers: { "Content-Type": "application/json" },
    }
  );
}

export const action = async ({ request }: ActionFunctionArgs) => {
  return handleSessionTokenAuth(request);
};

export const loader = async ({ request }: LoaderFunctionArgs) => {
  const url = new URL(request.url);
  if (
    url.pathname.endsWith("/session") ||
    request.headers.get("Authorization")?.startsWith("Bearer ")
  ) {
    return handleSessionTokenAuth(request);
  }

  const rawShop = url.searchParams.get("shop") || getDefaultStoreDomainSync();
  const cleanShop = (rawShop || "").includes(".") ? rawShop : `${rawShop}.myshopify.com`;
  const code = url.searchParams.get("code");
  const idToken = url.searchParams.get("id_token");
  const returnTo = url.searchParams.get("returnTo") || "/app";

  const appUrl = process.env.SHOPIFY_APP_URL || url.origin;
  const redirectUri = `${appUrl}/auth/callback`;
  const apiKey = process.env.SHOPIFY_API_KEY || "ff484160a48beda29e79144ee4e9a819";
  const scopes = process.env.SCOPES || "read_products,read_content,read_customers,read_orders,read_discounts";

  // 0. If a session token (id_token) is present, exchange it server-side via Token Exchange without top-level redirect
  if (!code && idToken) {
    const exchanged = await exchangeSessionTokenForAccessToken(cleanShop, idToken);
    if (exchanged) {
      return Response.redirect(`${appUrl}${returnTo.startsWith("/") ? returnTo : `/${returnTo}`}`);
    }
  }

  // 1. If no authorization code, initiate Shopify OAuth authorize with iframe breakout
  if (!code) {
    const authorizeUrl = `https://${cleanShop}/admin/oauth/authorize?client_id=${apiKey}&scope=${encodeURIComponent(scopes)}&redirect_uri=${encodeURIComponent(redirectUri)}`;

    return new Response(
      `<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="shopify-api-key" content="${apiKey}">
  <script src="https://cdn.shopify.com/shopifycloud/app-bridge.js"></script>
  <title>Redirecting to Shopify Authorization...</title>
  <script>
    try {
      if (window.shopify && typeof window.shopify.open === "function") {
        window.shopify.open(${JSON.stringify(authorizeUrl)}, "_top");
      } else if (window.top && window.top !== window) {
        window.top.location.href = ${JSON.stringify(authorizeUrl)};
      } else {
        window.location.href = ${JSON.stringify(authorizeUrl)};
      }
    } catch (e) {
      window.location.href = ${JSON.stringify(authorizeUrl)};
    }
  </script>
</head>
<body style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 80vh; background: #f8fafc; margin: 0;">
  <div style="text-align: center; max-width: 480px; padding: 32px; background: white; border-radius: 12px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); border: 1px solid #e2e8f0;">
    <div style="font-size: 32px; margin-bottom: 12px;">🔒</div>
    <h2 style="margin: 0 0 10px; color: #1e293b; font-size: 20px;">Connecting to Shopify</h2>
    <p style="color: #64748b; font-size: 14px; margin-bottom: 24px; line-height: 1.5;">
      Redirecting to authorize permissions for <strong>${cleanShop}</strong>. If the page does not open automatically, please click below:
    </p>
    <a href="${authorizeUrl}" target="_top" style="display: inline-block; padding: 12px 24px; background: #4f46e5; color: white; border-radius: 8px; text-decoration: none; font-weight: 600; font-size: 14px;">
      Authorize App on Shopify &rarr;
    </a>
  </div>
</body>
</html>`,
      {
        status: 200,
        headers: { "Content-Type": "text/html; charset=utf-8" },
      }
    );
  }

  // 2. Exchange authorization code for official offline access token
  let accessToken = "";
  const apiSecret = process.env.SHOPIFY_API_SECRET || "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";
  if (code && cleanShop && apiSecret) {
    try {
      const tokenParams = new URLSearchParams({
        client_id: apiKey,
        client_secret: apiSecret,
        code,
        expiring: "1",
      });

      const tokenRes = await fetch(`https://${cleanShop}/admin/oauth/access_token`, {
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: tokenParams.toString(),
      });

      if (tokenRes.ok) {
        const tokenData = await tokenRes.json();
        if (tokenData.access_token) {
          accessToken = tokenData.access_token;
          const refreshToken = tokenData.refresh_token || null;
          const expiresIn = Number(tokenData.expires_in || 3600);
          const tokenExpiresAt = new Date(Date.now() + expiresIn * 1000);
          const refreshTokenExpiresAt = refreshToken ? new Date(Date.now() + 90 * 24 * 60 * 60 * 1000) : undefined;
          const tokenUpdatedAt = new Date();

          console.log("[OAuth exchange SUCCESS]: Generated and stored expiring offline token for shop:", cleanShop);
          await registerShop({
            shopifyDomain: cleanShop,
            accessToken,
            refreshToken: refreshToken || undefined,
            tokenExpiresAt,
            refreshTokenExpiresAt,
            tokenUpdatedAt,
            scopes,
            isReinstall: true,
          });
        }
      } else {
        const errorText = await tokenRes.text();
        console.warn("[OAuth access_token HTTP error]:", tokenRes.status, errorText);
      }
    } catch (err: any) {
      console.warn("[OAuth token exchange warning]:", err?.message);
    }

    // Also store session record for maximum framework compatibility
    try {
      await (prisma as any).session?.upsert({
        where: { id: `offline_${cleanShop}` },
        update: {
          shop: cleanShop,
          state: "active",
          isOnline: false,
          scope: scopes,
          accessToken,
        },
        create: {
          id: `offline_${cleanShop}`,
          shop: cleanShop,
          state: "active",
          isOnline: false,
          scope: scopes,
          accessToken,
        },
      });
    } catch {}
  }

  // 3. Break back into Shopify Admin embedded frame
  const shopSubdomain = cleanShop.replace(/\.myshopify\.com$/i, "");
  const appHandle = process.env.SHOPIFY_APP_HANDLE || "commercebot-ai";

  // Clean sub-path for embedded app (e.g. /billing or root)
  const subPath = returnTo.replace(/^\/app\/?/, "");
  const embeddedSubPath = subPath ? (subPath.startsWith("/") ? subPath : `/${subPath}`) : "";

  // Direct official Shopify Admin embedded app URL (prevents /apps/app 404)
  const targetAppUrl = `https://admin.shopify.com/store/${shopSubdomain}/apps/${appHandle}${embeddedSubPath}`;

  return new Response(
    `<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="shopify-api-key" content="${apiKey}">
  <script src="https://cdn.shopify.com/shopifycloud/app-bridge.js"></script>
  <title>Redirecting to App...</title>
  <script>
    try {
      if (window.top && window.top !== window) {
        window.top.location.href = ${JSON.stringify(targetAppUrl)};
      } else {
        window.location.href = ${JSON.stringify(targetAppUrl)};
      }
    } catch (e) {
      window.location.href = ${JSON.stringify(targetAppUrl)};
    }
  </script>
</head>
<body style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 80vh; margin: 0; background: #f8fafc;">
  <div style="text-align: center; max-width: 420px; padding: 24px; background: white; border-radius: 12px; box-shadow: 0 4px 16px rgba(0,0,0,0.06);">
    <div style="font-size: 28px; margin-bottom: 8px;">✅</div>
    <h3 style="margin: 0 0 8px; color: #1e293b;">Authorization Completed</h3>
    <p style="color: #64748b; font-size: 14px; margin-bottom: 16px;">Loading your app dashboard...</p>
    <a href="${targetAppUrl}" target="_top" style="display: inline-block; padding: 10px 20px; background: #4f46e5; color: white; border-radius: 6px; text-decoration: none; font-weight: 600; font-size: 13px;">
      Click here to open app &rarr;
    </a>
  </div>
</body>
</html>`,
    {
      status: 200,
      headers: { "Content-Type": "text/html; charset=utf-8" },
    }
  );
};
