import { describe, it, expect } from "vitest";
import {
  validate,
  parse,
  GraphQLSchema,
  GraphQLObjectType,
  GraphQLString,
  GraphQLBoolean,
  GraphQLID,
  GraphQLList,
  GraphQLNonNull,
} from "graphql";
import depthLimit from "graphql-depth-limit";
import {
  createComplexityRule,
  simpleEstimator,
} from "graphql-query-complexity";

const DEPTH_LIMIT = 7;
const COST_LIMIT = 1000;

/**
 * 测试用 schema：包含递归类型以测试深度限制。
 *
 * 直接使用 graphql 包的 GraphQLSchema 构造，避免
 * @graphql-tools/schema 引入不同 graphql 实例导致
 * "Cannot use GraphQLSchema from another module or realm" 错误。
 */
const typeA: GraphQLObjectType = new GraphQLObjectType({
  name: "A",
  fields: () => ({
    a: { type: typeA },
    value: { type: GraphQLString },
  }),
});

const parentType = new GraphQLObjectType({
  name: "Parent",
  fields: {
    id: { type: new GraphQLNonNull(GraphQLID) },
    name: { type: new GraphQLNonNull(GraphQLString) },
  },
});

const childType = new GraphQLObjectType({
  name: "Child",
  fields: {
    id: { type: new GraphQLNonNull(GraphQLID) },
    name: { type: new GraphQLNonNull(GraphQLString) },
  },
});

const dashboardDataType = new GraphQLObjectType({
  name: "DashboardData",
  fields: {
    parent: { type: parentType },
    children: {
      type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(childType))),
    },
    degraded: { type: new GraphQLNonNull(GraphQLBoolean) },
  },
});

const queryType = new GraphQLObjectType({
  name: "Query",
  fields: {
    a: { type: typeA },
    dashboard: { type: dashboardDataType },
  },
});

const testSchema = new GraphQLSchema({ query: queryType });

function validateQuery(
  query: string,
  opts: { depth?: number; cost?: number } = {},
): ReturnType<typeof validate> {
  const rules: ReturnType<typeof depthLimit>[] = [];
  if (opts.depth !== undefined) {
    rules.push(depthLimit(opts.depth));
  }
  if (opts.cost !== undefined) {
    rules.push(
      createComplexityRule({
        maximumComplexity: opts.cost,
        estimators: [simpleEstimator({ defaultComplexity: 1 })],
        onComplete: () => {},
      }),
    );
  }
  return validate(testSchema, parse(query), rules);
}

describe("GraphQL 查询复杂度限制（测试用例 6）", () => {
  describe("深度限制", () => {
    it("depth=7 查询通过", () => {
      const query = `query {
        a {                    # 1
          a {                  # 2
            a {                # 3
              a {              # 4
                a {            # 5
                  a {          # 6
                    a {        # 7
                      value
                    }
                  }
                }
              }
            }
          }
        }
      }`;
      const errors = validateQuery(query, { depth: DEPTH_LIMIT });
      expect(errors).toHaveLength(0);
    });

    it("depth=8 查询被拒", () => {
      const query = `query {
        a {                    # 1
          a {                  # 2
            a {                # 3
              a {              # 4
                a {            # 5
                  a {          # 6
                    a {        # 7
                      a {      # 8
                        value
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }`;
      const errors = validateQuery(query, { depth: DEPTH_LIMIT });
      expect(errors.length).toBeGreaterThan(0);
      expect(errors[0]!.message).toContain("depth");
    });

    it("depth=1 查询通过", () => {
      const query = `query { a { value } }`;
      const errors = validateQuery(query, { depth: DEPTH_LIMIT });
      expect(errors).toHaveLength(0);
    });
  });

  describe("复杂度限制", () => {
    it("低复杂度查询通过", () => {
      const query = `query {
        dashboard {
          degraded
          parent { id name }
          children { id name }
        }
      }`;
      const errors = validateQuery(query, { cost: COST_LIMIT });
      expect(errors).toHaveLength(0);
    });

    it("cost > 1000 查询被拒", () => {
      const aliases: string[] = [];
      for (let i = 0; i < 501; i++) {
        aliases.push(`a${i}: dashboard { degraded }`);
      }
      const query = `query { ${aliases.join(" ")} }`;

      const errors = validateQuery(query, { cost: COST_LIMIT });
      expect(errors.length).toBeGreaterThan(0);
      expect(errors[0]!.message).toContain("complexity");
    });

    it("cost = 1000 查询通过（边界值）", () => {
      const aliases: string[] = [];
      for (let i = 0; i < 500; i++) {
        aliases.push(`a${i}: dashboard { degraded }`);
      }
      const query = `query { ${aliases.join(" ")} }`;

      const errors = validateQuery(query, { cost: COST_LIMIT });
      expect(errors).toHaveLength(0);
    });
  });

  describe("组合限制", () => {
    it("同时满足深度和复杂度限制的查询通过", () => {
      const query = `query {
        a {              # 1
          a {            # 2
            a {          # 3
              value
            }
          }
        }
        dashboard {
          degraded
          parent { id }
        }
      }`;
      const errors = validateQuery(query, {
        depth: DEPTH_LIMIT,
        cost: COST_LIMIT,
      });
      expect(errors).toHaveLength(0);
    });

    it("深度超限但复杂度未超限时被深度规则拒绝", () => {
      const query = `query {
        a {                    # 1
          a {                  # 2
            a {                # 3
              a {              # 4
                a {            # 5
                  a {          # 6
                    a {        # 7
                      a {      # 8
                        value
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }`;
      const errors = validateQuery(query, {
        depth: DEPTH_LIMIT,
        cost: COST_LIMIT,
      });
      const depthErrors = errors.filter((e) =>
        e.message.toLowerCase().includes("depth"),
      );
      expect(depthErrors.length).toBeGreaterThan(0);
    });
  });
});
