import { expect, it, describe } from "bun:test";

import { plainToInstance } from "class-transformer";
import { validate } from "class-validator";
import {
   BigqueryConnectionDto,
   ConnectionDto,
   DatabricksConnectionDto,
   PostgresConnectionDto,
   SnowflakeConnectionDto,
   MysqlConnectionDto,
} from "./connection.dto";

describe("dto/connection", () => {
   describe("Connection Validation", () => {
      it("should validate a valid MysqlConnection object", async () => {
         const validData = {
            host: "localhost",
            port: 3306,
            database: "testdb",
            user: "user",
            password: "pass",
         };
         const mysqlConnection = plainToInstance(MysqlConnectionDto, validData);

         const errors = await validate(mysqlConnection);
         expect(errors).toHaveLength(0);
      });

      it("should validate a valid PostgresConnection object", async () => {
         const validData = {
            host: "localhost",
            port: 5432,
            databaseName: "testdb",
            userName: "user",
            password: "pass",
            connectionString: "postgres://user:pass@localhost:5432/testdb",
         };
         const postgresConnection = plainToInstance(
            PostgresConnectionDto,
            validData,
         );

         const errors = await validate(postgresConnection);
         expect(errors).toHaveLength(0);
      });

      it("should return errors for invalid PostgresConnection object", async () => {
         const invalidData = {
            host: 123, // Invalid type
            port: "not-a-number", // Invalid type
         };
         const postgresConnection = plainToInstance(
            PostgresConnectionDto,
            invalidData,
         );

         const errors = await validate(postgresConnection);
         expect(errors).not.toHaveLength(0);
         expect(errors).toHaveLength(2);
      });

      it("should validate a valid BigqueryConnection object", async () => {
         const validData = {
            defaultProjectId: "default-project",
            billingProjectId: "billing-project",
            location: "US",
            serviceAccountKeyJson: "{}",
            maximumBytesBilled: "1000000",
            queryTimeoutMilliseconds: "1000",
         };
         const bigqueryConnection = plainToInstance(
            BigqueryConnectionDto,
            validData,
         );

         const errors = await validate(bigqueryConnection);
         expect(errors).toHaveLength(0);
      });

      it("should validate a valid SnowflakeConnection object", async () => {
         const validData = {
            account: "my-account",
            username: "user",
            password: "pass",
            privateKey:
               "-----BEGIN PRIVATE KEY-----\\nabc\\n-----END PRIVATE KEY-----",
            privateKeyPass: "secret",
            warehouse: "my-warehouse",
            database: "my-database",
            schema: "my-schema",
            role: "analyst",
            responseTimeoutMilliseconds: 5000,
         };
         const snowflakeConnection = plainToInstance(
            SnowflakeConnectionDto,
            validData,
         );

         const errors = await validate(snowflakeConnection);
         expect(errors).toHaveLength(0);
      });

      it("should validate a valid DatabricksConnection object", async () => {
         const validData = {
            host: "dbc-xxxxxxxx-xxxx.cloud.databricks.com",
            path: "/sql/1.0/warehouses/abc123",
            token: "dapiXXXX",
            oauthClientId: "client-id",
            oauthClientSecret: "client-secret",
            defaultCatalog: "main",
            defaultSchema: "default",
            setupSQL: "USE CATALOG main",
         };
         const databricksConnection = plainToInstance(
            DatabricksConnectionDto,
            validData,
         );

         const errors = await validate(databricksConnection);
         expect(errors).toHaveLength(0);
      });

      it("should return errors for invalid DatabricksConnection object", async () => {
         const invalidData = {
            host: 123, // Invalid type
            path: false, // Invalid type
         };
         const databricksConnection = plainToInstance(
            DatabricksConnectionDto,
            invalidData,
         );

         const errors = await validate(databricksConnection);
         expect(errors).toHaveLength(2);
      });

      it("should validate a valid Connection object with databricks type", async () => {
         const validData = {
            name: "My Databricks Connection",
            type: "databricks",
            databricksConnection: {
               host: "dbc-xxxxxxxx-xxxx.cloud.databricks.com",
               path: "/sql/1.0/warehouses/abc123",
               token: "dapiXXXX",
            },
         };
         const connection = plainToInstance(ConnectionDto, validData);

         const errors = await validate(connection);
         expect(errors).toHaveLength(0);
      });

      it("should validate a valid Connection object with postgres type", async () => {
         const validData = {
            name: "My Postgres Connection",
            type: "postgres",
            postgresConnection: {
               host: "localhost",
               port: 5432,
               databaseName: "testdb",
               userName: "user",
               password: "pass",
            },
         };
         const connection = plainToInstance(ConnectionDto, validData);

         const errors = await validate(connection);
         expect(errors).toHaveLength(0);
      });

      it("should return errors for invalid Connection object", async () => {
         const invalidData = {
            type: "invalid-type", // Invalid enum value
            postgresConnection: {
               port: "invalid-port", // Invalid type
            },
         };
         const connection = plainToInstance(ConnectionDto, invalidData);

         const errors = await validate(connection);
         expect(errors).not.toHaveLength(0);
         expect(errors.length).toBeGreaterThan(0);
      });
   });
});
