import db from "../db.server";
import { RULES } from "./rules";
import { adminLog } from "./admin-logger.server";

interface ShopifyAdmin {
  graphql: (query: string, options?: { variables?: Record<string, unknown> }) => Promise<Response>;
}

interface MetafieldConfig {
  [key: string]: boolean | string;
}

interface SyncResult {
  success: boolean;
  error: string | null;
}

const MAX_METAFIELD_JSON_SIZE = 30000; // 30KB safety margin under 32KB Shopify limit

async function getAppInstallationId(admin: ShopifyAdmin): Promise<string> {
  const response = await admin.graphql(
    `#graphql
    query {
      currentAppInstallation {
        id
      }
    }`,
  );
  const data = await response.json();
  return data.data.currentAppInstallation.id;
}

export async function syncRulesToMetafield(
  admin: ShopifyAdmin,
  shopId: string,
): Promise<SyncResult> {
  const [shopRules, shopRecord] = await Promise.all([
    db.shopRule.findMany({ where: { shopId } }),
    db.shop.findUnique({ where: { id: shopId }, select: { debugMode: true } }),
  ]);

  const debugMode = shopRecord?.debugMode ?? false;
  const rulesMap = new Map(shopRules.map((r) => [r.ruleKey, r]));

  const config: MetafieldConfig = {};

  for (const rule of RULES) {
    const shopRule = rulesMap.get(rule.key);
    const enabled = shopRule?.enabled ?? rule.defaultEnabled;
    config[rule.key] = enabled;

    if (rule.hasCustomValue && shopRule?.customValue) {
      config[`${rule.key}_value`] = shopRule.customValue;
    }
  }

  const configJson = JSON.stringify(config);

  // Validate payload size before sending to Shopify
  if (configJson.length > MAX_METAFIELD_JSON_SIZE) {
    await adminLog("error", `Metafield payload too large: ${configJson.length} bytes`, { shopId });
    return {
      success: false,
      error: `La configuration depasse la taille maximale autorisee (${Math.round(configJson.length / 1000)}KB / ${MAX_METAFIELD_JSON_SIZE / 1000}KB). Reduisez les valeurs personnalisees.`,
    };
  }

  try {
    const ownerId = await getAppInstallationId(admin);

    const response = await admin.graphql(
      `#graphql
      mutation SetCleanSerpConfig($metafields: [MetafieldsSetInput!]!) {
        metafieldsSet(metafields: $metafields) {
          metafields {
            id
            namespace
            key
          }
          userErrors {
            field
            message
          }
        }
      }`,
      {
        variables: {
          metafields: [
            {
              namespace: "cs_x9k2m",
              key: "rules",
              type: "json",
              value: configJson,
              ownerId,
            },
            {
              namespace: "cs_x9k2m",
              key: "active",
              type: "boolean",
              value: "true",
              ownerId,
            },
            {
              namespace: "cs_x9k2m",
              key: "debug_mode",
              type: "boolean",
              value: debugMode ? "true" : "false",
              ownerId,
            },
          ],
        },
      },
    );

    const data = await response.json();

    if (data.data?.metafieldsSet?.userErrors?.length > 0) {
      const errorMsg = data.data.metafieldsSet.userErrors[0].message;
      await adminLog("error", `Metafield sync failed: ${errorMsg}`, { shopId });
      return { success: false, error: `Erreur Shopify: ${errorMsg}` };
    }

    await db.shop.update({
      where: { id: shopId },
      data: { lastSyncedAt: new Date() },
    });

    return { success: true, error: null };
  } catch (error) {
    const errorMsg =
      error instanceof Error ? error.message : "Erreur inconnue";
    await adminLog("error", `Metafield sync network error: ${errorMsg}`, { shopId });
    return {
      success: false,
      error: `Erreur de synchronisation: ${errorMsg}`,
    };
  }
}

export async function clearShopMetafields(admin: ShopifyAdmin): Promise<void> {
  try {
    const ownerId = await getAppInstallationId(admin);

    await admin.graphql(
      `#graphql
      mutation ClearCleanSerpConfig($metafields: [MetafieldsSetInput!]!) {
        metafieldsSet(metafields: $metafields) {
          metafields {
            id
          }
          userErrors {
            field
            message
          }
        }
      }`,
      {
        variables: {
          metafields: [
            {
              namespace: "cs_x9k2m",
              key: "active",
              type: "boolean",
              value: "false",
              ownerId,
            },
          ],
        },
      },
    );
  } catch (error) {
    console.error(
      "Failed to clear shop metafields:",
      error instanceof Error ? error.message : error,
    );
  }
}
