import { MigrationInterface, QueryRunner } from "typeorm";

/**
 * Converts the `role` column on the `user` table from varchar to a proper
 * PostgreSQL enum type.
 *
 * Existing rows are safe: the varchar values 'user' and 'admin' inserted by
 * CreateUserTable1661234567890 match the enum members exactly, so the USING
 * cast succeeds without any data transformation.
 *
 * down() reverts cleanly by casting back to text and dropping the enum type.
 */
export class ConvertRoleToEnum1701234567890 implements MigrationInterface {
    public async up(queryRunner: QueryRunner): Promise<void> {
        // Create the enum type if it doesn't already exist
        await queryRunner.query(`
            DO $$ BEGIN
                CREATE TYPE user_role_enum AS ENUM ('user', 'admin');
            EXCEPTION
                WHEN duplicate_object THEN null;
            END $$;
        `);

        // Ensure any existing role values that differ only by whitespace or
        // casing are normalised before the cast
        await queryRunner.query(`
            UPDATE "user"
            SET "role" = LOWER(TRIM("role"))
            WHERE "role" IS NOT NULL;
        `);

        // Drop the varchar default before retyping — PostgreSQL cannot cast it
        // automatically and will reject the ALTER COLUMN otherwise
        await queryRunner.query(`
            ALTER TABLE "user"
                ALTER COLUMN "role" DROP DEFAULT;
        `);

        // Convert the column — existing 'user' and 'admin' values cast directly
        await queryRunner.query(`
            ALTER TABLE "user"
            ALTER COLUMN "role" TYPE user_role_enum
            USING "role"::user_role_enum;
        `);

        // Re-apply the default using the enum literal
        await queryRunner.query(`
            ALTER TABLE "user"
            ALTER COLUMN "role" SET DEFAULT 'user'::user_role_enum;
        `);
    }

    public async down(queryRunner: QueryRunner): Promise<void> {
        // Drop the enum default first so the column can be retyped
        await queryRunner.query(`
            ALTER TABLE "user"
                ALTER COLUMN "role" DROP DEFAULT;
        `);

        // Cast enum values back to plain text
        await queryRunner.query(`
            ALTER TABLE "user"
            ALTER COLUMN "role" TYPE varchar
            USING "role"::text;
        `);

        // Restore the original varchar default
        await queryRunner.query(`
            ALTER TABLE "user"
                ALTER COLUMN "role" SET DEFAULT 'user';
        `);

        // Drop the enum type — only safe once no column references it
        await queryRunner.query(`
            DROP TYPE IF EXISTS user_role_enum;
        `);
    }
}