import { getShopWithDecryptedToken, getValidAdminAccessToken } from "../../services/shop.server";
import { ShopifyAPIError, TenantAccessDeniedError } from "../security/errors";
import { logger } from "../security/logger";

export interface AdminClientConfig {
  shopifyDomain: string;
}

export class ShopifyAdminClient {
  private shopifyDomain: string;

  constructor(config: AdminClientConfig) {
    if (!config.shopifyDomain) {
      throw new TenantAccessDeniedError("shopifyDomain is required for ShopifyAdminClient");
    }
    this.shopifyDomain = config.shopifyDomain.toLowerCase().trim();
  }

  private async getAccessToken(): Promise<string> {
    const validToken = await getValidAdminAccessToken(this.shopifyDomain);
    if (!validToken) {
      const shop = await getShopWithDecryptedToken(this.shopifyDomain);
      if (!shop || shop.uninstalledAt || !shop.decryptedAccessToken) {
        throw new TenantAccessDeniedError(`No active decrypted access token for shop ${this.shopifyDomain}`);
      }
      return shop.decryptedAccessToken;
    }
    return validToken;
  }

  /**
   * Executes a typed GraphQL query/mutation against Shopify Admin GraphQL API.
   */
  async graphql<T = any>(query: string, variables: Record<string, any> = {}): Promise<T> {
    const accessToken = await this.getAccessToken();
    const endpoint = `https://${this.shopifyDomain}/admin/api/2025-01/graphql.json`;

    try {
      const response = await fetch(endpoint, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-Shopify-Access-Token": accessToken,
        },
        body: JSON.stringify({ query, variables }),
      });

      if (!response.ok) {
        const errText = await response.text();
        logger.error(`Shopify GraphQL HTTP ${response.status} error`, { shop: this.shopifyDomain, status: response.status, body: errText });
        throw new ShopifyAPIError(`Shopify Admin API HTTP ${response.status}`, response.status, { body: errText });
      }

      const json = await response.json();
      if (json.errors && json.errors.length > 0) {
        logger.error("Shopify GraphQL Errors", { shop: this.shopifyDomain, errors: json.errors });
        throw new ShopifyAPIError(json.errors[0].message || "GraphQL Execution Error", 400, { errors: json.errors });
      }

      return json.data as T;
    } catch (error: any) {
      if (error instanceof ShopifyAPIError || error instanceof TenantAccessDeniedError) {
        throw error;
      }
      logger.error("Failed to connect to Shopify Admin API", error, { shop: this.shopifyDomain });
      throw new ShopifyAPIError(error.message || "Network error connecting to Shopify API", 500);
    }
  }

  // --- Product Admin API Methods ---

  async getProducts(first = 20): Promise<any> {
    const query = `#graphql
      query getProducts($first: Int!) {
        products(first: $first) {
          edges {
            node {
              id
              title
              handle
              description
              featuredImage { url }
              priceRangeV2 {
                minVariantPrice { amount currencyCode }
                maxVariantPrice { amount currencyCode }
              }
              variants(first: 10) {
                edges {
                  node {
                    id
                    title
                    price
                    inventoryQuantity
                  }
                }
              }
            }
          }
        }
      }
    `;
    return this.graphql(query, { first });
  }

  async searchProducts(searchQuery: string, first = 10): Promise<any> {
    const query = `#graphql
      query searchProducts($query: String!, $first: Int!) {
        products(first: $first, query: $query) {
          edges {
            node {
              id
              title
              handle
              description
              featuredImage { url }
              priceRangeV2 {
                minVariantPrice { amount currencyCode }
                maxVariantPrice { amount currencyCode }
              }
              variants(first: 5) {
                edges {
                  node {
                    id
                    title
                    price
                    inventoryQuantity
                  }
                }
              }
            }
          }
        }
      }
    `;
    return this.graphql(query, { query: searchQuery, first });
  }

  // --- Customer Admin API Methods ---

  async createCustomer(data: {
    firstName?: string;
    lastName?: string;
    email: string;
    phone?: string;
    note?: string;
  }): Promise<any> {
    // 1. Try GraphQL Customer Creation
    try {
      const mutation = `#graphql
        mutation customerCreate($input: CustomerInput!) {
          customerCreate(input: $input) {
            customer {
              id
              firstName
              lastName
              email
              phone
              numberOfOrders
            }
            userErrors {
              field
              message
            }
          }
        }
      `;
      const input: Record<string, any> = {
        email: data.email,
      };
      if (data.firstName) input.firstName = data.firstName;
      if (data.lastName) input.lastName = data.lastName;
      if (data.phone) input.phone = data.phone;
      if (data.note) input.note = data.note;

      const res = await this.graphql(mutation, { input });
      if (res?.customerCreate?.customer?.id) {
        return res;
      }
    } catch (gqlErr) {
      logger.warn("GraphQL customerCreate failed, attempting REST API fallback", { error: gqlErr });
    }

    // 2. Try REST API Customer Creation
    try {
      const accessToken = await this.getAccessToken();
      const endpoint = `https://${this.shopifyDomain}/admin/api/2025-01/customers.json`;
      const response = await fetch(endpoint, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-Shopify-Access-Token": accessToken,
        },
        body: JSON.stringify({
          customer: {
            first_name: data.firstName || "",
            last_name: data.lastName || "",
            email: data.email,
            phone: data.phone || undefined,
            note: data.note || "Created via ShopPilot AI Chatbot",
            verified_email: true,
            send_email_welcome: false,
          },
        }),
      });

      if (response.ok) {
        const json = await response.json();
        if (json?.customer?.id) {
          return {
            customerCreate: {
              customer: {
                id: `gid://shopify/Customer/${json.customer.id}`,
                firstName: json.customer.first_name,
                lastName: json.customer.last_name,
                email: json.customer.email,
                phone: json.customer.phone,
                numberOfOrders: json.customer.orders_count || 0,
              },
              userErrors: [],
            },
          };
        }
      }
    } catch (restErr) {
      logger.error("REST customer creation error", restErr);
    }

    return null;
  }

  async findCustomerByEmail(email: string): Promise<any> {
    const query = `#graphql
      query findCustomerByEmail($query: String!) {
        customers(first: 1, query: $query) {
          edges {
            node {
              id
              firstName
              lastName
              email
              phone
              numberOfOrders
              orders(first: 5) {
                edges {
                  node {
                    id
                    name
                    processedAt
                    financialStatus
                    fulfillmentStatus
                    totalPriceSet { presentmentMoney { amount currencyCode } }
                  }
                }
              }
            }
          }
        }
      }
    `;
    return this.graphql(query, { query: `email:${email}` });
  }

  async getCustomer(customerId: string): Promise<any> {
    const query = `#graphql
      query getCustomer($id: ID!) {
        customer(id: $id) {
          id
          firstName
          lastName
          email
          phone
          numberOfOrders
          orders(first: 10) {
            edges {
              node {
                id
                name
                processedAt
                financialStatus
                fulfillmentStatus
                totalPriceSet { presentmentMoney { amount currencyCode } }
              }
            }
          }
        }
      }
    `;
    return this.graphql(query, { id: customerId });
  }

  // --- Order Admin API Methods ---

  async getOrders(first = 10): Promise<any> {
    const query = `#graphql
      query getOrders($first: Int!) {
        orders(first: $first, sortKey: CREATED_AT, reverse: true) {
          edges {
            node {
              id
              name
              createdAt
              displayFinancialStatus
              displayFulfillmentStatus
              totalPriceSet { presentmentMoney { amount currencyCode } }
              lineItems(first: 5) {
                edges {
                  node {
                    title
                    quantity
                  }
                }
              }
            }
          }
        }
      }
    `;
    return this.graphql(query, { first });
  }

  async getOrder(orderId: string): Promise<any> {
    const query = `#graphql
      query getOrder($id: ID!) {
        order(id: $id) {
          id
          name
          createdAt
          cancelledAt
          cancelReason
          displayFinancialStatus
          displayFulfillmentStatus
          totalPriceSet { presentmentMoney { amount currencyCode } }
          shippingAddress {
            address1
            city
            province
            country
            zip
          }
          lineItems(first: 10) {
            edges {
              node {
                title
                quantity
                originalUnitPriceSet { presentmentMoney { amount currencyCode } }
              }
            }
          }
        }
      }
    `;
    return this.graphql(query, { id: orderId });
  }

  /**
   * Safe Order Cancellation GraphQL mutation.
   */
  async cancelOrder(orderId: string, reason = "CUSTOMER", notifyCustomer = true): Promise<any> {
    const mutation = `#graphql
      mutation orderCancel($orderId: ID!, $reason: OrderCancelReason!, $notifyCustomer: Boolean!) {
        orderCancel(orderId: $orderId, reason: $reason, notifyCustomer: $notifyCustomer) {
          job { id status }
          userErrors { field message }
        }
      }
    `;
    return this.graphql(mutation, { orderId, reason, notifyCustomer });
  }

  // --- Content, Shop & Policy Admin API Methods ---

  /**
   * Fetches shop metadata, primary domain, contact emails, and legal policies.
   */
  async getShopDetails(): Promise<any> {
    const query = `#graphql
      query getShopDetails {
        shop {
          name
          email
          contactEmail
          myshopifyDomain
          url
          primaryDomain {
            url
            host
            sslEnabled
          }
        }
      }
    `;
    return this.graphql(query);
  }

  /**
   * Fetches all blogs and articles from the connected Shopify store.
   */
  async getStoreBlogsAndArticles(): Promise<any> {
    const query = `#graphql
      query getStoreBlogsAndArticles {
        shop {
          myshopifyDomain
          primaryDomain {
            url
            host
            sslEnabled
          }
        }
        blogs(first: 50) {
          edges {
            node {
              id
              title
              handle
              articles(first: 100) {
                edges {
                  node {
                    id
                    title
                    handle
                    summary
                    body
                    image {
                      url
                    }
                    author {
                      name
                    }
                    tags
                    publishedAt
                  }
                }
              }
            }
          }
        }
      }
    `;
    return this.graphql(query);
  }

  /**
   * Fetches all online store pages (e.g. Contact Us, About Us, FAQ).
   */
  async getStorePages(): Promise<any> {
    const query = `#graphql
      query getStorePages {
        shop {
          myshopifyDomain
          primaryDomain {
            url
            host
            sslEnabled
          }
        }
        pages(first: 100) {
          edges {
            node {
              id
              title
              handle
              body
              bodySummary
              createdAt
              updatedAt
            }
          }
        }
      }
    `;
    return this.graphql(query);
  }

  /**
   * Fetches active discount codes and automatic discounts configured in Shopify Admin.
   */
  async getActiveDiscounts(first = 25): Promise<any> {
    const query = `#graphql
      query getActiveDiscounts($first: Int!) {
        codeDiscountNodes(first: $first, query: "status:active") {
          edges {
            node {
              id
              codeDiscount {
                ... on DiscountCodeBasic {
                  title
                  status
                  summary
                  startsAt
                  endsAt
                  codes(first: 5) {
                    edges {
                      node {
                        code
                      }
                    }
                  }
                  customerGets {
                    value {
                      ... on DiscountPercentage {
                        percentage
                      }
                      ... on DiscountAmount {
                        amount {
                          amount
                          currencyCode
                        }
                      }
                    }
                  }
                }
                ... on DiscountCodeBxgy {
                  title
                  status
                  summary
                  startsAt
                  endsAt
                  codes(first: 5) {
                    edges {
                      node {
                        code
                      }
                    }
                  }
                }
                ... on DiscountCodeFreeShipping {
                  title
                  status
                  summary
                  startsAt
                  endsAt
                  codes(first: 5) {
                    edges {
                      node {
                        code
                      }
                    }
                  }
                }
                ... on DiscountCodeApp {
                  title
                  status
                  codes(first: 5) {
                    edges {
                      node {
                        code
                      }
                    }
                  }
                }
              }
            }
          }
        }
        automaticDiscountNodes(first: $first, query: "status:active") {
          edges {
            node {
              id
              automaticDiscount {
                ... on DiscountAutomaticBasic {
                  title
                  status
                  summary
                  startsAt
                  endsAt
                }
                ... on DiscountAutomaticBxgy {
                  title
                  status
                  summary
                  startsAt
                  endsAt
                }
                ... on DiscountAutomaticFreeShipping {
                  title
                  status
                  summary
                  startsAt
                  endsAt
                }
                ... on DiscountAutomaticApp {
                  title
                  status
                }
              }
            }
          }
        }
      }
    `;
    return this.graphql(query, { first });
  }
}

