#!/usr/bin/env tclsh

set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_execsql_test_on_specific_db {:memory:} alter-column-rename-and-type {
    CREATE TABLE t (a INTEGER);
    CREATE INDEX i ON t (a);
    ALTER TABLE t ALTER COLUMN a TO b BLOB;
    SELECT sql FROM sqlite_schema;
} {
    "CREATE TABLE t (b BLOB)"
    "CREATE INDEX i ON t (b)"
}

do_execsql_test_in_memory_any_error fail-alter-column-primary-key {
    CREATE TABLE t (a);
    ALTER TABLE t ALTER COLUMN a TO a PRIMARY KEY;
}

do_execsql_test_in_memory_any_error fail-alter-column-unique {
    CREATE TABLE t (a);
    ALTER TABLE t ALTER COLUMN a TO a UNIQUE;
}

do_execsql_test_on_specific_db {:memory:} alter-table-rename-pk-column {
    CREATE TABLE customers (cust_id INTEGER PRIMARY KEY, cust_name TEXT);
    INSERT INTO customers VALUES (1, 'Alice'), (2, 'Bob');
    
    ALTER TABLE customers RENAME COLUMN cust_id TO customer_id;
    
    SELECT sql FROM sqlite_schema WHERE name = 'customers';
    SELECT customer_id, cust_name FROM customers ORDER BY customer_id;
} {
    "CREATE TABLE customers (customer_id INTEGER PRIMARY KEY, cust_name TEXT)"
    "1|Alice"
    "2|Bob"
}

do_execsql_test_on_specific_db {:memory:} alter-table-rename-composite-pk {
    CREATE TABLE products (category TEXT, prod_code TEXT, name TEXT, PRIMARY KEY (category, prod_code));
    INSERT INTO products VALUES ('Electronics', 'E001', 'Laptop');
    
    ALTER TABLE products RENAME COLUMN prod_code TO product_code;
    
    SELECT sql FROM sqlite_schema WHERE name = 'products';
    SELECT category, product_code, name FROM products;
} {
    "CREATE TABLE products (category TEXT, product_code TEXT, name TEXT, PRIMARY KEY (category, product_code))"
    "Electronics|E001|Laptop"
}

# Foreign key child column rename
do_execsql_test_on_specific_db {:memory:} alter-table-rename-fk-child {
    CREATE TABLE parent (id INTEGER PRIMARY KEY);
    CREATE TABLE child (cid INTEGER PRIMARY KEY, pid INTEGER, FOREIGN KEY (pid) REFERENCES parent(id));
    INSERT INTO parent VALUES (1);
    INSERT INTO child VALUES (1, 1);
    
    ALTER TABLE child RENAME COLUMN pid TO parent_id;
    
    SELECT sql FROM sqlite_schema WHERE name = 'child';
} {
    "CREATE TABLE child (cid INTEGER PRIMARY KEY, parent_id INTEGER, FOREIGN KEY (parent_id) REFERENCES parent (id))"
}

# Foreign key parent column rename - critical test
do_execsql_test_on_specific_db {:memory:} alter-table-rename-fk-parent {
    CREATE TABLE orders (order_id INTEGER PRIMARY KEY, date TEXT);
    CREATE TABLE items (item_id INTEGER PRIMARY KEY, oid INTEGER, FOREIGN KEY (oid) REFERENCES orders(order_id));
    
    ALTER TABLE orders RENAME COLUMN order_id TO ord_id;
    
    SELECT sql FROM sqlite_schema WHERE name = 'orders';
    SELECT sql FROM sqlite_schema WHERE name = 'items';
} {
    "CREATE TABLE orders (ord_id INTEGER PRIMARY KEY, date TEXT)"
    "CREATE TABLE items (item_id INTEGER PRIMARY KEY, oid INTEGER, FOREIGN KEY (oid) REFERENCES orders (ord_id))"
}

# Composite foreign key parent rename
do_execsql_test_on_specific_db {:memory:} alter-table-rename-composite-fk-parent {
    CREATE TABLE products (cat TEXT, code TEXT, PRIMARY KEY (cat, code));
    CREATE TABLE inventory (id INTEGER PRIMARY KEY, cat TEXT, code TEXT, FOREIGN KEY (cat, code) REFERENCES products(cat, code));
    
    ALTER TABLE products RENAME COLUMN code TO sku;
    
    SELECT sql FROM sqlite_schema WHERE name = 'products';
    SELECT sql FROM sqlite_schema WHERE name = 'inventory';
} {
    "CREATE TABLE products (cat TEXT, sku TEXT, PRIMARY KEY (cat, sku))"
    "CREATE TABLE inventory (id INTEGER PRIMARY KEY, cat TEXT, code TEXT, FOREIGN KEY (cat, code) REFERENCES products (cat, sku))"
}

# Multiple foreign keys to same parent
do_execsql_test_on_specific_db {:memory:} alter-table-rename-multiple-fks {
    CREATE TABLE users (uid INTEGER PRIMARY KEY);
    CREATE TABLE messages (mid INTEGER PRIMARY KEY, sender INTEGER, receiver INTEGER, 
                          FOREIGN KEY (sender) REFERENCES users(uid),
                          FOREIGN KEY (receiver) REFERENCES users(uid));
    
    ALTER TABLE users RENAME COLUMN uid TO user_id;
    
    SELECT sql FROM sqlite_schema WHERE name = 'messages';
} {
    "CREATE TABLE messages (mid INTEGER PRIMARY KEY, sender INTEGER, receiver INTEGER, FOREIGN KEY (sender) REFERENCES users (user_id), FOREIGN KEY (receiver) REFERENCES users (user_id))"
}

# Self-referencing foreign key
do_execsql_test_on_specific_db {:memory:} alter-table-rename-self-ref-fk {
    CREATE TABLE employees (emp_id INTEGER PRIMARY KEY, manager_id INTEGER, 
                           FOREIGN KEY (manager_id) REFERENCES employees(emp_id));
    
    ALTER TABLE employees RENAME COLUMN emp_id TO employee_id;
    
    SELECT sql FROM sqlite_schema WHERE name = 'employees';
} {
    "CREATE TABLE employees (employee_id INTEGER PRIMARY KEY, manager_id INTEGER, FOREIGN KEY (manager_id) REFERENCES employees (employee_id))"
}

# Chain of FK renames - parent is both PK and referenced
do_execsql_test_on_specific_db {:memory:} alter-table-rename-fk-chain {
    CREATE TABLE t1 (a INTEGER PRIMARY KEY);
    CREATE TABLE t2 (b INTEGER PRIMARY KEY, a_ref INTEGER, FOREIGN KEY (a_ref) REFERENCES t1(a));
    CREATE TABLE t3 (c INTEGER PRIMARY KEY, b_ref INTEGER, FOREIGN KEY (b_ref) REFERENCES t2(b));
    
    ALTER TABLE t1 RENAME COLUMN a TO a_new;
    ALTER TABLE t2 RENAME COLUMN b TO b_new;
    
    SELECT sql FROM sqlite_schema WHERE name = 't2';
    SELECT sql FROM sqlite_schema WHERE name = 't3';
} {
    "CREATE TABLE t2 (b_new INTEGER PRIMARY KEY, a_ref INTEGER, FOREIGN KEY (a_ref) REFERENCES t1 (a_new))"
    "CREATE TABLE t3 (c INTEGER PRIMARY KEY, b_ref INTEGER, FOREIGN KEY (b_ref) REFERENCES t2 (b_new))"
}

# FK with ON DELETE/UPDATE actions
do_execsql_test_on_specific_db {:memory:} alter-table-rename-fk-actions {
    CREATE TABLE parent (pid INTEGER PRIMARY KEY);
    CREATE TABLE child (cid INTEGER PRIMARY KEY, pid INTEGER, 
                       FOREIGN KEY (pid) REFERENCES parent(pid) ON DELETE CASCADE ON UPDATE RESTRICT);
    
    ALTER TABLE parent RENAME COLUMN pid TO parent_id;
    
    SELECT sql FROM sqlite_schema WHERE name = 'child';
} {
    "CREATE TABLE child (cid INTEGER PRIMARY KEY, pid INTEGER, FOREIGN KEY (pid) REFERENCES parent (parent_id) ON DELETE CASCADE ON UPDATE RESTRICT)"
}

# FK with DEFERRABLE
do_execsql_test_on_specific_db {:memory:} alter-table-rename-fk-deferrable {
    CREATE TABLE parent (id INTEGER PRIMARY KEY);
    CREATE TABLE child (id INTEGER PRIMARY KEY, pid INTEGER, 
                       FOREIGN KEY (pid) REFERENCES parent(id) DEFERRABLE INITIALLY DEFERRED);
    
    ALTER TABLE parent RENAME COLUMN id TO parent_id;
    
    SELECT sql FROM sqlite_schema WHERE name = 'child';
} {
    "CREATE TABLE child (id INTEGER PRIMARY KEY, pid INTEGER, FOREIGN KEY (pid) REFERENCES parent (parent_id) DEFERRABLE INITIALLY DEFERRED)"
}

# Rename with quoted identifiers in FK
do_execsql_test_on_specific_db {:memory:} alter-table-rename-fk-quoted {
    CREATE TABLE "parent table" ("parent id" INTEGER PRIMARY KEY);
    CREATE TABLE child (id INTEGER PRIMARY KEY, pid INTEGER, 
                       FOREIGN KEY (pid) REFERENCES "parent table"("parent id"));
    
    ALTER TABLE "parent table" RENAME COLUMN "parent id" TO "new id";
    
    SELECT sql FROM sqlite_schema WHERE name = 'child';
} {
    "CREATE TABLE child (id INTEGER PRIMARY KEY, pid INTEGER, FOREIGN KEY (pid) REFERENCES \"parent table\" (\"new id\"))"
}

# Verify FK constraint still works after rename
do_execsql_test_on_specific_db {:memory:} alter-table-fk-constraint-after-rename {
    PRAGMA foreign_keys = ON;
    CREATE TABLE parent (id INTEGER PRIMARY KEY);
    CREATE TABLE child (id INTEGER PRIMARY KEY, pid INTEGER, FOREIGN KEY (pid) REFERENCES parent(id));
    INSERT INTO parent VALUES (1);
    INSERT INTO child VALUES (1, 1);
    
    ALTER TABLE parent RENAME COLUMN id TO parent_id;
    
    -- This should work
    INSERT INTO child VALUES (2, 1);
    SELECT COUNT(*) FROM child;
} {
    "2"
}

# FK constraint violation after rename should still fail
do_execsql_test_in_memory_any_error alter-table-fk-violation-after-rename {
    PRAGMA foreign_keys = ON;
    CREATE TABLE parent (id INTEGER PRIMARY KEY);
    CREATE TABLE child (id INTEGER PRIMARY KEY, pid INTEGER, FOREIGN KEY (pid) REFERENCES parent(id));
    INSERT INTO parent VALUES (1);
    
    ALTER TABLE parent RENAME COLUMN id TO parent_id;
    
    -- This should fail with FK violation
    INSERT INTO child VALUES (1, 999);
}

# Complex scenario with multiple table constraints
do_execsql_test_on_specific_db {:memory:} alter-table-rename-complex-constraints {
    CREATE TABLE t (
        a INTEGER, 
        b TEXT, 
        c REAL,
        PRIMARY KEY (a, b),
        UNIQUE (b, c),
        FOREIGN KEY (a) REFERENCES t(a)
    );
    
    ALTER TABLE t RENAME COLUMN a TO x;
    ALTER TABLE t RENAME COLUMN b TO y;
    
    SELECT sql FROM sqlite_schema WHERE name = 't';
} {
    "CREATE TABLE t (x INTEGER, y TEXT, c REAL, PRIMARY KEY (x, y), UNIQUE (y, c), FOREIGN KEY (x) REFERENCES t (x))"
}

# Rename column that appears in both PK and FK
do_execsql_test_on_specific_db {:memory:} alter-table-rename-pk-and-fk {
    CREATE TABLE parent (id INTEGER PRIMARY KEY);
    CREATE TABLE child (
        id INTEGER PRIMARY KEY,
        parent_ref INTEGER,
        FOREIGN KEY (id) REFERENCES parent(id),
        FOREIGN KEY (parent_ref) REFERENCES parent(id)
    );
    
    ALTER TABLE parent RENAME COLUMN id TO pid;
    
    SELECT sql FROM sqlite_schema WHERE name = 'child';
} {
    "CREATE TABLE child (id INTEGER PRIMARY KEY, parent_ref INTEGER, FOREIGN KEY (id) REFERENCES parent (pid), FOREIGN KEY (parent_ref) REFERENCES parent (pid))"
}
