package com.cube.sql;

import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;

import java.util.*;

/**
 * Tests for SQL Parser
 */
public class SQLParserTest {
    
    @Test
    public void testParseSelectAll() {
        String sql = "SELECT * FROM users.profiles WHERE id = 'user-1'";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.SELECT, parsed.getType());
        assertEquals("users", parsed.getKeyspace());
        assertEquals("profiles", parsed.getTable());
        assertTrue(parsed.getSelectColumns().contains("*"));
        assertEquals("user-1", parsed.getWhereClause().get("id"));
    }
    
    @Test
    public void testParseSelectColumns() {
        String sql = "SELECT name, email, age FROM users.profiles WHERE id = 'user-1'";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.SELECT, parsed.getType());
        assertEquals(3, parsed.getSelectColumns().size());
        assertTrue(parsed.getSelectColumns().contains("name"));
        assertTrue(parsed.getSelectColumns().contains("email"));
        assertTrue(parsed.getSelectColumns().contains("age"));
    }
    
    @Test
    public void testParseSelectDefaultKeyspace() {
        String sql = "SELECT * FROM profiles WHERE id = 'user-1'";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals("default", parsed.getKeyspace());
        assertEquals("profiles", parsed.getTable());
    }
    
    @Test
    public void testParseSelectMultipleConditions() {
        String sql = "SELECT * FROM users WHERE id = 'user-1' AND status = 'active'";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(2, parsed.getWhereClause().size());
        assertEquals("user-1", parsed.getWhereClause().get("id"));
        assertEquals("active", parsed.getWhereClause().get("status"));
    }
    
    @Test
    public void testParseInsert() {
        String sql = "INSERT INTO users.profiles (id, name, email) VALUES ('user-1', 'Alice', 'alice@example.com')";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.INSERT, parsed.getType());
        assertEquals("users", parsed.getKeyspace());
        assertEquals("profiles", parsed.getTable());
        assertEquals(3, parsed.getColumns().size());
        assertEquals("user-1", parsed.getColumns().get("id"));
        assertEquals("Alice", parsed.getColumns().get("name"));
        assertEquals("alice@example.com", parsed.getColumns().get("email"));
    }
    
    @Test
    public void testParseInsertWithQuotes() {
        String sql = "INSERT INTO messages (id, text) VALUES ('msg-1', 'Hello \"World\"')";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.INSERT, parsed.getType());
        assertEquals("msg-1", parsed.getColumns().get("id"));
        assertTrue(parsed.getColumns().get("text").contains("Hello"));
    }
    
    @Test
    public void testParseUpdate() {
        String sql = "UPDATE users.profiles SET name='Alice Johnson', age='31' WHERE id='user-1'";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.UPDATE, parsed.getType());
        assertEquals("users", parsed.getKeyspace());
        assertEquals("profiles", parsed.getTable());
        assertEquals(2, parsed.getColumns().size());
        assertEquals("Alice Johnson", parsed.getColumns().get("name"));
        assertEquals("31", parsed.getColumns().get("age"));
        assertEquals("user-1", parsed.getWhereClause().get("id"));
    }
    
    @Test
    public void testParseDelete() {
        String sql = "DELETE FROM users.profiles WHERE id='user-1'";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.DELETE, parsed.getType());
        assertEquals("users", parsed.getKeyspace());
        assertEquals("profiles", parsed.getTable());
        assertEquals("user-1", parsed.getWhereClause().get("id"));
    }
    
    @Test
    public void testParseCreateTable() {
        String sql = "CREATE TABLE users.profiles (id TEXT PRIMARY KEY, name TEXT, email TEXT)";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.CREATE_TABLE, parsed.getType());
        assertEquals("users", parsed.getKeyspace());
        assertEquals("profiles", parsed.getTable());
        assertEquals(3, parsed.getColumnDefinitions().size());
        assertEquals("TEXT", parsed.getColumnDefinitions().get("id"));
        assertEquals("TEXT", parsed.getColumnDefinitions().get("name"));
        assertEquals("TEXT", parsed.getColumnDefinitions().get("email"));
        assertEquals("id", parsed.getPrimaryKey());
    }
    
    @Test
    public void testParseCreateTableImplicitPrimaryKey() {
        String sql = "CREATE TABLE products (sku TEXT, name TEXT, price TEXT)";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.CREATE_TABLE, parsed.getType());
        assertEquals("default", parsed.getKeyspace());
        assertEquals("products", parsed.getTable());
        assertEquals("sku", parsed.getPrimaryKey());
    }
    
    @Test
    public void testParseDropTable() {
        String sql = "DROP TABLE users.profiles";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.DROP_TABLE, parsed.getType());
        assertEquals("users", parsed.getKeyspace());
        assertEquals("profiles", parsed.getTable());
    }
    
    @Test
    public void testParseDescribe() {
        String sql = "DESCRIBE users.profiles";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.DESCRIBE, parsed.getType());
        assertEquals("users", parsed.getKeyspace());
        assertEquals("profiles", parsed.getTable());
    }
    
    @Test
    public void testParseDescribeShort() {
        String sql = "DESC users.profiles";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.DESCRIBE, parsed.getType());
    }
    
    @Test
    public void testParseShowTables() {
        String sql = "SHOW TABLES";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.SHOW_TABLES, parsed.getType());
    }
    
    @Test
    public void testParseSemicolon() {
        String sql = "SELECT * FROM users WHERE id = 'user-1';";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.SELECT, parsed.getType());
        assertEquals("user-1", parsed.getWhereClause().get("id"));
    }
    
    @Test
    public void testParseCaseInsensitive() {
        String sql = "select * from users where id = 'user-1'";
        SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
        
        assertEquals(SQLParser.SQLType.SELECT, parsed.getType());
    }
    
    @Test
    public void testParseInvalidSQL() {
        assertThrows(IllegalArgumentException.class, () -> {
            SQLParser.parse("INVALID SQL STATEMENT");
        });
    }
    
    @Test
    public void testParseEmptySQL() {
        assertThrows(IllegalArgumentException.class, () -> {
            SQLParser.parse("");
        });
    }
    
    @Test
    public void testParseNullSQL() {
        assertThrows(IllegalArgumentException.class, () -> {
            SQLParser.parse(null);
        });
    }
}
