using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.Data.SQLite;
using System.Linq;
using System.Threading.Tasks;
using Excel = Microsoft.Office.Interop.Excel;

namespace TableMagic.Skills
{
    public class ExcelDatabaseSkill : ISkill
    {
        public string Name => "ExcelDatabase";
        public string Description => "数据库连接技能,支持连接多种数据库并提取数据到Excel";

        public List<SkillTool> GetTools()
        {
            return new List<SkillTool>
            {
                new SkillTool
                {
                    Name = "connect_database",
                    Description = "连接数据库并获取表名列表。支持SQL Server、MySQL、PostgreSQL、Access、SQLite等数据库。当用户要求连接数据库时使用此工具。",
                    Parameters = new Dictionary<string, object>
                    {
                        { "type", "object" },
                        { "properties", new Dictionary<string, object>
                            {
                                { "dbType", new { type = "string", description = "数据库类型:sqlserver/mysql/postgresql/access/sqlite" } },
                                { "connectionString", new { type = "string", description = "数据库连接字符串或文件路径" } }
                            }
                        }
                    },
                    RequiredParameters = new List<string> { "dbType", "connectionString" }
                },
                new SkillTool
                {
                    Name = "execute_query",
                    Description = "执行SQL查询并将结果写入Excel。当用户要求查询数据库、执行SQL时使用此工具。",
                    Parameters = new Dictionary<string, object>
                    {
                        { "type", "object" },
                        { "properties", new Dictionary<string, object>
                            {
                                { "dbType", new { type = "string", description = "数据库类型:sqlserver/mysql/postgresql/access/sqlite" } },
                                { "connectionString", new { type = "string", description = "数据库连接字符串" } },
                                { "query", new { type = "string", description = "SQL查询语句" } },
                                { "outputSheetName", new { type = "string", description = "输出工作表名称(可选,默认'查询结果')" } }
                            }
                        }
                    },
                    RequiredParameters = new List<string> { "dbType", "connectionString", "query" }
                },
                new SkillTool
                {
                    Name = "export_table_to_excel",
                    Description = "将数据库表导出到Excel工作表。当用户要求导出数据库表时使用此工具。",
                    Parameters = new Dictionary<string, object>
                    {
                        { "type", "object" },
                        { "properties", new Dictionary<string, object>
                            {
                                { "dbType", new { type = "string", description = "数据库类型" } },
                                { "connectionString", new { type = "string", description = "数据库连接字符串" } },
                                { "tableName", new { type = "string", description = "要导出的表名" } },
                                { "outputSheetName", new { type = "string", description = "输出工作表名称(可选)" } }
                            }
                        }
                    },
                    RequiredParameters = new List<string> { "dbType", "connectionString", "tableName" }
                },
                new SkillTool
                {
                    Name = "get_table_structure",
                    Description = "获取数据库表的结构信息(字段名、类型等)。当用户要求查看表结构时使用此工具。",
                    Parameters = new Dictionary<string, object>
                    {
                        { "type", "object" },
                        { "properties", new Dictionary<string, object>
                            {
                                { "dbType", new { type = "string", description = "数据库类型" } },
                                { "connectionString", new { type = "string", description = "数据库连接字符串" } },
                                { "tableName", new { type = "string", description = "表名" } }
                            }
                        }
                    },
                    RequiredParameters = new List<string> { "dbType", "connectionString", "tableName" }
                }
            };
        }

        public async Task<SkillResult> ExecuteToolAsync(string toolName, Dictionary<string, object> arguments)
        {
            try
            {
                switch (toolName)
                {
                    case "connect_database":
                        return await ConnectDatabaseAsync(arguments);
                    case "execute_query":
                        return await ExecuteQueryAsync(arguments);
                    case "export_table_to_excel":
                        return await ExportTableToExcelAsync(arguments);
                    case "get_table_structure":
                        return await GetTableStructureAsync(arguments);
                    default:
                        return new SkillResult { Success = false, Error = $"Tool {toolName} not implemented in ExcelDatabaseSkill" };
                }
            }
            catch (Exception ex)
            {
                return new SkillResult { Success = false, Error = ex.Message };
            }
        }

        private async Task<SkillResult> ConnectDatabaseAsync(Dictionary<string, object> arguments)
        {
            return await Task.Run(() =>
            {
                var dbType = arguments["dbType"].ToString().ToLower();
                var connectionString = arguments["connectionString"].ToString();

                try
                {
                    var tableNames = GetTableNames(dbType, connectionString);
                    return new SkillResult 
                    { 
                        Success = true, 
                        Content = $"数据库连接成功,共 {tableNames.Count} 张表:\n{string.Join("\n", tableNames)}" 
                    };
                }
                catch (Exception ex)
                {
                    return new SkillResult { Success = false, Error = $"数据库连接失败:{ex.Message}" };
                }
            });
        }

        private async Task<SkillResult> ExecuteQueryAsync(Dictionary<string, object> arguments)
        {
            return await Task.Run(() =>
            {
                var dbType = arguments["dbType"].ToString().ToLower();
                var connectionString = arguments["connectionString"].ToString();
                var query = arguments["query"].ToString();
                var outputSheetName = arguments.ContainsKey("outputSheetName") 
                    ? arguments["outputSheetName"].ToString() 
                    : "查询结果";

                try
                {
                    var dataTable = ExecuteQuery(dbType, connectionString, query);
                    WriteDataTableToExcel(dataTable, outputSheetName);
                    return new SkillResult 
                    { 
                        Success = true, 
                        Content = $"查询执行成功,共 {dataTable.Rows.Count} 行数据已写入工作表 '{outputSheetName}'" 
                    };
                }
                catch (Exception ex)
                {
                    return new SkillResult { Success = false, Error = $"查询执行失败:{ex.Message}" };
                }
            });
        }

        private async Task<SkillResult> ExportTableToExcelAsync(Dictionary<string, object> arguments)
        {
            var dbType = arguments["dbType"].ToString().ToLower();
            var connectionString = arguments["connectionString"].ToString();
            var tableName = arguments["tableName"].ToString();
            var outputSheetName = arguments.ContainsKey("outputSheetName") 
                ? arguments["outputSheetName"].ToString() 
                : tableName;

            return await ExecuteQueryAsync(new Dictionary<string, object>
            {
                { "dbType", dbType },
                { "connectionString", connectionString },
                { "query", $"SELECT * FROM [{tableName}]" },
                { "outputSheetName", outputSheetName }
            });
        }

        private async Task<SkillResult> GetTableStructureAsync(Dictionary<string, object> arguments)
        {
            return await Task.Run(() =>
            {
                var dbType = arguments["dbType"].ToString().ToLower();
                var connectionString = arguments["connectionString"].ToString();
                var tableName = arguments["tableName"].ToString();

                try
                {
                    var query = dbType switch
                    {
                        "sqlserver" => $"SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '{tableName}'",
                        "mysql" => $"DESCRIBE {tableName}",
                        "postgresql" => $"SELECT column_name, data_type, character_maximum_length, is_nullable FROM information_schema.columns WHERE table_name = '{tableName}'",
                        "access" or "sqlite" => $"PRAGMA table_info({tableName})",
                        _ => throw new NotSupportedException($"不支持的数据库类型: {dbType}")
                    };

                    var dataTable = ExecuteQuery(dbType, connectionString, query);
                    WriteDataTableToExcel(dataTable, $"{tableName}_结构");
                    return new SkillResult 
                    { 
                        Success = true, 
                        Content = $"表 '{tableName}' 结构已导出,共 {dataTable.Rows.Count} 个字段" 
                    };
                }
                catch (Exception ex)
                {
                    return new SkillResult { Success = false, Error = $"获取表结构失败:{ex.Message}" };
                }
            });
        }

        private List<string> GetTableNames(string dbType, string connectionString)
        {
            var tableNames = new List<string>();

            switch (dbType)
            {
                case "access":
                    using (var conn = new OleDbConnection(connectionString))
                    {
                        conn.Open();
                        var schema = conn.GetSchema("Tables");
                        foreach (DataRow row in schema.Rows)
                        {
                            if (row["TABLE_TYPE"].ToString() == "TABLE")
                                tableNames.Add(row["TABLE_NAME"].ToString());
                        }
                    }
                    break;

                case "sqlite":
                    using (var conn = new SQLiteConnection(connectionString))
                    {
                        conn.Open();
                        using (var cmd = new SQLiteCommand("SELECT name FROM sqlite_master WHERE type='table'", conn))
                        using (var reader = cmd.ExecuteReader())
                        {
                            while (reader.Read())
                                tableNames.Add(reader["name"].ToString());
                        }
                    }
                    break;

                case "sqlserver":
                case "mysql":
                case "postgresql":
                    var query = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'";
                    var dt = ExecuteQuery(dbType, connectionString, query);
                    foreach (DataRow row in dt.Rows)
                        tableNames.Add(row[0].ToString());
                    break;

                default:
                    throw new NotSupportedException($"不支持的数据库类型: {dbType}");
            }

            return tableNames;
        }

        private DataTable ExecuteQuery(string dbType, string connectionString, string query)
        {
            var dataTable = new DataTable();

            switch (dbType)
            {
                case "access":
                    using (var conn = new OleDbConnection(connectionString))
                    using (var adapter = new OleDbDataAdapter(query, conn))
                    {
                        adapter.Fill(dataTable);
                    }
                    break;

                case "sqlite":
                    using (var conn = new SQLiteConnection(connectionString))
                    using (var adapter = new SQLiteDataAdapter(query, conn))
                    {
                        adapter.Fill(dataTable);
                    }
                    break;

                case "sqlserver":
                    using (var conn = new System.Data.SqlClient.SqlConnection(connectionString))
                    using (var adapter = new System.Data.SqlClient.SqlDataAdapter(query, conn))
                    {
                        adapter.Fill(dataTable);
                    }
                    break;

                case "mysql":
                    using (var conn = new MySql.Data.MySqlClient.MySqlConnection(connectionString))
                    using (var adapter = new MySql.Data.MySqlClient.MySqlDataAdapter(query, conn))
                    {
                        adapter.Fill(dataTable);
                    }
                    break;

                case "postgresql":
                    using (var conn = new Npgsql.NpgsqlConnection(connectionString))
                    using (var adapter = new Npgsql.NpgsqlDataAdapter(query, conn))
                    {
                        adapter.Fill(dataTable);
                    }
                    break;

                default:
                    throw new NotSupportedException($"不支持的数据库类型: {dbType}");
            }

            return dataTable;
        }

        private void WriteDataTableToExcel(DataTable dataTable, string sheetName)
        {
            var workbook = ThisAddIn.app.ActiveWorkbook;

            ThisAddIn.app.ScreenUpdating = false;
            ThisAddIn.app.DisplayAlerts = false;

            Excel.Worksheet sheet;
            
            var existingNames = new List<string>();
            foreach (Excel.Worksheet ws in workbook.Worksheets) existingNames.Add(ws.Name);
            
            string actualSheetName = sheetName;
            if (existingNames.Any(n => string.Equals(n, sheetName, StringComparison.OrdinalIgnoreCase)))
            {
                int suffix = 2;
                while (existingNames.Any(n => string.Equals(n, $"{sheetName}_{suffix}", StringComparison.OrdinalIgnoreCase)))
                {
                    suffix++;
                }
                actualSheetName = $"{sheetName}_{suffix}";
            }
            
            sheet = workbook.Worksheets.Add(After: workbook.Worksheets[workbook.Worksheets.Count]);
            sheet.Name = actualSheetName;

            for (int c = 0; c < dataTable.Columns.Count; c++)
            {
                sheet.Cells[1, c + 1].Value = dataTable.Columns[c].ColumnName;
                sheet.Cells[1, c + 1].Font.Bold = true;
            }

            for (int r = 0; r < dataTable.Rows.Count; r++)
            {
                for (int c = 0; c < dataTable.Columns.Count; c++)
                {
                    sheet.Cells[r + 2, c + 1].Value = dataTable.Rows[r][c];
                }
            }

            sheet.UsedRange.Columns.AutoFit();
            sheet.Activate();

            ThisAddIn.app.ScreenUpdating = true;
            ThisAddIn.app.DisplayAlerts = true;
        }
    }
}