import { logger } from "../security/logger";
import { ShopifyAPIError } from "../security/errors";

export interface StorefrontClientConfig {
  shopifyDomain: string;
  storefrontAccessToken?: string;
}

export class ShopifyStorefrontClient {
  private shopifyDomain: string;
  private storefrontAccessToken: string;

  constructor(config: StorefrontClientConfig) {
    this.shopifyDomain = config.shopifyDomain.toLowerCase().trim();
    this.storefrontAccessToken = config.storefrontAccessToken || "";
  }

  /**
   * Executes a GraphQL query against Shopify Storefront API.
   */
  async graphql<T = any>(query: string, variables: Record<string, any> = {}): Promise<T> {
    const endpoint = `https://${this.shopifyDomain}/api/2026-07/graphql.json`;
    const headers: Record<string, string> = {
      "Content-Type": "application/json",
    };

    if (this.storefrontAccessToken) {
      headers["X-Shopify-Storefront-Access-Token"] = this.storefrontAccessToken;
    }

    try {
      const response = await fetch(endpoint, {
        method: "POST",
        headers,
        body: JSON.stringify({ query, variables }),
      });

      if (!response.ok) {
        throw new ShopifyAPIError(`Storefront API HTTP ${response.status}`, response.status);
      }

      const json = await response.json();
      if (json.errors) {
        throw new ShopifyAPIError(json.errors[0].message || "Storefront GraphQL Error", 400);
      }

      return json.data as T;
    } catch (error: any) {
      logger.warn("Storefront API connection warning", { shop: this.shopifyDomain, error: error.message });
      throw error;
    }
  }

  // --- Cart Operations ---

  async createCart(lines: Array<{ merchandiseId: string; quantity: number }> = []): Promise<any> {
    const mutation = `#graphql
      mutation cartCreate($input: CartInput!) {
        cartCreate(input: $input) {
          cart {
            id
            checkoutUrl
            totalQuantity
            cost { totalAmount { amount currencyCode } }
          }
          userErrors { field message }
        }
      }
    `;
    return this.graphql(mutation, { input: { lines } });
  }

  async addCartLines(cartId: string, lines: Array<{ merchandiseId: string; quantity: number }>): Promise<any> {
    const mutation = `#graphql
      mutation cartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!) {
        cartLinesAdd(cartId: $cartId, lines: $lines) {
          cart {
            id
            checkoutUrl
            totalQuantity
            cost { totalAmount { amount currencyCode } subtotalAmount { amount currencyCode } }
            discountCodes { code applicable }
          }
          userErrors { field message }
        }
      }
    `;
    return this.graphql(mutation, { cartId, lines });
  }

  async updateCartDiscountCodes(cartId: string, discountCodes: string[]): Promise<any> {
    const mutation = `#graphql
      mutation cartDiscountCodesUpdate($cartId: ID!, $discountCodes: [String!]) {
        cartDiscountCodesUpdate(cartId: $cartId, discountCodes: $discountCodes) {
          cart {
            id
            checkoutUrl
            totalQuantity
            cost {
              totalAmount { amount currencyCode }
              subtotalAmount { amount currencyCode }
              totalDiscountAmount { amount currencyCode }
            }
            discountCodes { code applicable }
          }
          userErrors { field message }
        }
      }
    `;
    return this.graphql(mutation, { cartId, discountCodes });
  }

  async getCart(cartId: string): Promise<any> {
    const query = `#graphql
      query getCart($cartId: ID!) {
        cart(id: $cartId) {
          id
          checkoutUrl
          totalQuantity
          cost {
            totalAmount { amount currencyCode }
            subtotalAmount { amount currencyCode }
            totalDiscountAmount { amount currencyCode }
          }
          discountCodes { code applicable }
          lines(first: 20) {
            edges {
              node {
                id
                quantity
                merchandise {
                  ... on ProductVariant {
                    id
                    title
                    price { amount currencyCode }
                    product { title handle }
                  }
                }
              }
            }
          }
        }
      }
    `;
    return this.graphql(query, { cartId });
  }

  // --- Customer Authentication Operations ---

  async customerAccessTokenCreate(input: { email: string; password: string }): Promise<any> {
    const mutation = `#graphql
      mutation customerAccessTokenCreate($input: CustomerAccessTokenCreateInput!) {
        customerAccessTokenCreate(input: $input) {
          customerAccessToken {
            accessToken
            expiresAt
          }
          customerUserErrors {
            code
            field
            message
          }
        }
      }
    `;
    return this.graphql(mutation, { input });
  }

  async customerCreate(input: { firstName?: string; lastName?: string; email: string; password: string }): Promise<any> {
    const mutation = `#graphql
      mutation customerCreate($input: CustomerCreateInput!) {
        customerCreate(input: $input) {
          customer {
            id
            firstName
            lastName
            email
            phone
          }
          customerUserErrors {
            code
            field
            message
          }
        }
      }
    `;
    return this.graphql(mutation, { input });
  }

  async customerRecover(email: string): Promise<any> {
    const mutation = `#graphql
      mutation customerRecover($email: String!) {
        customerRecover(email: $email) {
          customerUserErrors {
            code
            field
            message
          }
        }
      }
    `;
    return this.graphql(mutation, { email });
  }

  async customerAccessTokenDelete(customerAccessToken: string): Promise<any> {
    const mutation = `#graphql
      mutation customerAccessTokenDelete($customerAccessToken: String!) {
        customerAccessTokenDelete(customerAccessToken: $customerAccessToken) {
          deletedAccessToken
          deletedCustomerAccessTokenId
          userErrors {
            field
            message
          }
        }
      }
    `;
    return this.graphql(mutation, { customerAccessToken });
  }

  async getCustomer(customerAccessToken: string): Promise<any> {
    const query = `#graphql
      query getCustomer($customerAccessToken: String!) {
        customer(customerAccessToken: $customerAccessToken) {
          id
          firstName
          lastName
          email
          phone
          orders(first: 10, sortKey: PROCESSED_AT, reverse: true) {
            edges {
              node {
                id
                name
                orderNumber
                processedAt
                financialStatus
                fulfillmentStatus
                totalPrice { amount currencyCode }
                statusUrl
              }
            }
          }
        }
      }
    `;
    return this.graphql(query, { customerAccessToken });
  }

  async getStorePolicies(): Promise<any> {
    const query = `#graphql
      query getStorePolicies {
        shop {
          privacyPolicy { id title body url }
          refundPolicy { id title body url }
          shippingPolicy { id title body url }
          termsOfService { id title body url }
          subscriptionPolicy { id title body url }
        }
      }
    `;
    return this.graphql(query);
  }
}

