import { Config, ConfigHelpers } from "../../src/config/Config.ts";

describe("Config Comprehensive Tests", () => {
  let originalEnv;

  beforeEach(() => {
    // Save original environment
    originalEnv = { ...process.env };

    // Reset Config singleton
    Config.reset();

    // Set clean test environment
    process.env.NODE_ENV = "test";
    delete process.env.DEBUG;
    delete process.env.GITHUB_ACTIONS;
    delete process.env.TRAVIS;
    delete process.env.CIRCLECI;
    delete process.env.CI;
  });

  afterEach(() => {
    // Restore original environment
    process.env = originalEnv;
    Config.reset();
  });

  describe("CI Provider Detection", () => {
    it("should detect GitHub Actions", () => {
      process.env.GITHUB_ACTIONS = "true";
      Config.getInstance();

      expect(ConfigHelpers.isCI()).toBe(true);
      // Test the private detectCIProvider method indirectly through CI detection
      expect(process.env.GITHUB_ACTIONS).toBe("true");
    });

    it("should detect Travis CI", () => {
      process.env.TRAVIS = "true";
      Config.getInstance();

      expect(ConfigHelpers.isCI()).toBe(true);
      expect(process.env.TRAVIS).toBe("true");
    });

    it("should detect CircleCI", () => {
      process.env.CIRCLECI = "true";
      Config.getInstance();

      expect(ConfigHelpers.isCI()).toBe(true);
      expect(process.env.CIRCLECI).toBe("true");
    });

    it("should detect generic CI", () => {
      process.env.CI = "true";
      Config.getInstance();

      expect(ConfigHelpers.isCI()).toBe(true);
      expect(process.env.CI).toBe("true");
    });

    it("should not detect CI in normal environment", () => {
      // No CI environment variables set
      Config.getInstance();

      expect(ConfigHelpers.isCI()).toBe(false);
    });
  });

  describe("Environment Detection", () => {
    it("should detect development environment", () => {
      process.env.NODE_ENV = "development";
      Config.reset();

      expect(ConfigHelpers.isDev()).toBe(true);
      expect(ConfigHelpers.isProd()).toBe(false);
      expect(ConfigHelpers.isTest()).toBe(false);
    });

    it("should detect production environment", () => {
      process.env.NODE_ENV = "production";
      Config.reset();

      expect(ConfigHelpers.isProd()).toBe(true);
      expect(ConfigHelpers.isDev()).toBe(false);
      expect(ConfigHelpers.isTest()).toBe(false);
    });

    it("should detect test environment", () => {
      process.env.NODE_ENV = "test";
      Config.reset();

      expect(ConfigHelpers.isTest()).toBe(true);
      expect(ConfigHelpers.isDev()).toBe(false);
      expect(ConfigHelpers.isProd()).toBe(false);
    });

    it("should detect DXT environment", () => {
      process.env.NODE_ENV = "dxt";
      Config.reset();

      expect(ConfigHelpers.isDXT()).toBe(true);
      expect(ConfigHelpers.isDev()).toBe(false);
    });
  });

  describe("ConfigHelpers convenience methods", () => {
    it("should provide debug flag", () => {
      process.env.DEBUG = "true";
      process.env.NODE_ENV = "development";
      Config.reset();

      expect(ConfigHelpers.shouldDebug()).toBe(true);
    });

    it("should disable debug in DXT mode", () => {
      process.env.DEBUG = "true";
      process.env.NODE_ENV = "dxt";
      Config.reset();

      expect(ConfigHelpers.shouldDebug()).toBe(false);
    });

    it("should provide cache flag", () => {
      process.env.CACHE_DISABLED = "false";
      Config.reset();

      expect(ConfigHelpers.shouldUseCache()).toBe(true);
    });

    it("should disable cache when CACHE_DISABLED=true", () => {
      process.env.CACHE_DISABLED = "true";
      Config.reset();

      expect(ConfigHelpers.shouldUseCache()).toBe(false);
    });

    it("should provide info logging flag", () => {
      process.env.NODE_ENV = "development";
      Config.reset();

      expect(ConfigHelpers.shouldLogInfo()).toBe(true);
    });

    it("should disable info logging in test mode", () => {
      process.env.NODE_ENV = "test";
      Config.reset();

      expect(ConfigHelpers.shouldLogInfo()).toBe(false);
    });

    it("should disable info logging in DXT mode", () => {
      process.env.NODE_ENV = "dxt";
      Config.reset();

      expect(ConfigHelpers.shouldLogInfo()).toBe(false);
    });
  });

  describe("WordPress Configuration Detection", () => {
    it("should detect WordPress config when site URL is present", () => {
      process.env.WORDPRESS_SITE_URL = "https://example.com";
      process.env.WORDPRESS_USERNAME = "testuser";
      process.env.WORDPRESS_APP_PASSWORD = "test-password";
      Config.reset();

      expect(ConfigHelpers.hasWordPressConfig()).toBe(true);
    });

    it("should not detect WordPress config when site URL is missing", () => {
      delete process.env.WORDPRESS_SITE_URL;
      Config.reset();

      expect(ConfigHelpers.hasWordPressConfig()).toBe(false);
    });
  });

  describe("Timeout Configuration", () => {
    it("should provide operation timeout", () => {
      const timeout = ConfigHelpers.getTimeout("operation");
      expect(typeof timeout).toBe("number");
      expect(timeout).toBeGreaterThan(0);
    });

    it("should provide longer upload timeout", () => {
      const opTimeout = ConfigHelpers.getTimeout("operation");
      const uploadTimeout = ConfigHelpers.getTimeout("upload");

      expect(uploadTimeout).toBeGreaterThan(opTimeout);
      expect(uploadTimeout).toBe(opTimeout * 5);
    });

    it("should provide test timeout", () => {
      const testTimeout = ConfigHelpers.getTimeout("test");
      expect(typeof testTimeout).toBe("number");
      expect(testTimeout).toBeGreaterThan(0);
    });

    it("should provide shorter test timeout in CI", () => {
      process.env.CI = "true";
      Config.reset();

      const testTimeout = ConfigHelpers.getTimeout("test");
      expect(testTimeout).toBe(30000); // 30 seconds in CI
    });

    it("should provide longer test timeout in development", () => {
      process.env.NODE_ENV = "development";
      delete process.env.CI;
      Config.reset();

      const testTimeout = ConfigHelpers.getTimeout("test");
      expect(testTimeout).toBe(10000); // 10 seconds in dev
    });

    it("should default to operation timeout for unknown types", () => {
      const defaultTimeout = ConfigHelpers.getTimeout();
      const operationTimeout = ConfigHelpers.getTimeout("operation");

      expect(defaultTimeout).toBe(operationTimeout);
    });
  });

  describe("Config Singleton Behavior", () => {
    it("should return the same instance", () => {
      const instance1 = Config.getInstance();
      const instance2 = Config.getInstance();

      expect(instance1).toBe(instance2);
    });

    it("should reset and create new instance", () => {
      const instance1 = Config.getInstance();
      Config.reset();
      const instance2 = Config.getInstance();

      expect(instance1).not.toBe(instance2);
    });

    it("should preserve config across multiple accesses", () => {
      process.env.DEBUG = "true";
      Config.reset();

      const shouldDebug1 = ConfigHelpers.shouldDebug();
      const shouldDebug2 = ConfigHelpers.shouldDebug();

      expect(shouldDebug1).toBe(shouldDebug2);
    });
  });

  describe("Environment Edge Cases", () => {
    it("should handle undefined NODE_ENV", () => {
      delete process.env.NODE_ENV;
      Config.reset();

      expect(() => Config.getInstance()).not.toThrow();
      expect(ConfigHelpers.isDev()).toBe(true); // Defaults to development
      expect(ConfigHelpers.isProd()).toBe(false);
      expect(ConfigHelpers.isTest()).toBe(false);
    });

    it("should handle empty string NODE_ENV", () => {
      process.env.NODE_ENV = "";
      Config.reset();

      expect(() => Config.getInstance()).not.toThrow();
    });

    it("should handle invalid NODE_ENV values", () => {
      process.env.NODE_ENV = "invalid";
      Config.reset();

      expect(() => Config.getInstance()).not.toThrow();
      expect(ConfigHelpers.isDev()).toBe(false);
      expect(ConfigHelpers.isProd()).toBe(false);
      expect(ConfigHelpers.isTest()).toBe(false);
    });
  });

  describe("Debug Configuration", () => {
    it("should enable debug when DEBUG=true", () => {
      process.env.DEBUG = "true";
      process.env.NODE_ENV = "development";
      Config.reset();

      expect(ConfigHelpers.shouldDebug()).toBe(true);
    });

    it("should disable debug when DEBUG=false", () => {
      process.env.DEBUG = "false";
      process.env.NODE_ENV = "development";
      Config.reset();

      expect(ConfigHelpers.shouldDebug()).toBe(false);
    });

    it("should disable debug when DEBUG is undefined", () => {
      delete process.env.DEBUG;
      process.env.NODE_ENV = "development";
      Config.reset();

      expect(ConfigHelpers.shouldDebug()).toBe(false);
    });
  });

  describe("Cache Configuration", () => {
    it("should enable cache by default", () => {
      delete process.env.CACHE_DISABLED;
      Config.reset();

      expect(ConfigHelpers.shouldUseCache()).toBe(true);
    });

    it("should handle various falsy values for cache disabled", () => {
      const falsyValues = ["false", "0", ""];

      falsyValues.forEach((value) => {
        process.env.CACHE_DISABLED = value;
        Config.reset();
        expect(ConfigHelpers.shouldUseCache()).toBe(true);
      });
    });

    it("should handle various truthy values for cache disabled", () => {
      const truthyValues = ["true", "1", "yes", "enable", "enabled"];

      truthyValues.forEach((value) => {
        process.env.CACHE_DISABLED = value;
        Config.reset();
        expect(ConfigHelpers.shouldUseCache()).toBe(false);
      });
    });

    it("should NOT treat 'disable' and 'disabled' as truthy values for security", () => {
      const falsyValues = ["disable", "disabled", "false", "0", "no", "off"];

      falsyValues.forEach((value) => {
        process.env.CACHE_DISABLED = value;
        Config.reset();
        expect(ConfigHelpers.shouldUseCache()).toBe(true); // Cache should be enabled
      });
    });
  });
});
