using System.Data;
using System.Data.SQLite;
using Dapper;

namespace OCES.Resonance.Core;

public static class Database
{
    static readonly string DefaultConnectionString = "Data Source=default.db;Version=3;";
    
    /// <summary>
    /// 获取数据库连接
    /// </summary>
    /// <param name="dbName">数据库名称（不含扩展名）</param>
    /// <returns>数据库连接</returns>
    public static IDbConnection GetConnection(string dbName = "default")
    {
        var connectionString = $"Data Source={dbName}.db;Version=3;";
        return new SQLiteConnection(connectionString);
    }
    
    /// <summary>
    /// 初始化数据库表结构
    /// </summary>
    public static void InitializeDatabase()
    {
        using var connection = GetConnection();
        connection.Open();
        
        const string sql = @"
            CREATE TABLE IF NOT EXISTS audio_files (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                unique_id TEXT NOT NULL UNIQUE,
                short_id TEXT,
                md5 TEXT NOT NULL,
                path TEXT NOT NULL,
                filename TEXT NOT NULL,
                folder TEXT NOT NULL,
                directory TEXT NOT NULL,
                duration REAL NOT NULL,
                total_samples INTEGER NOT NULL,
                bit_depth INTEGER NOT NULL,
                channels INTEGER NOT NULL,
                sample_rate INTEGER NOT NULL,
                type TEXT NOT NULL,
                date_added TEXT NOT NULL,
                original_modification_date TEXT NOT NULL,
                origination_time TEXT NOT NULL,
                
                bpm REAL,
                frame_rate TEXT,
                timecode INTEGER,
                description TEXT,
                category TEXT,
                subcategory TEXT,
                cat_id TEXT,
                category_full TEXT,
                genre TEXT,
                style TEXT,
                mood TEXT,
                keywords TEXT,
                rating INTEGER,
                artist TEXT,
                composer TEXT,
                designer TEXT,
                recordist TEXT,
                publisher TEXT,
                manufacturer TEXT,
                originator TEXT,
                originator_ref TEXT,
                project_name TEXT,
                library TEXT,
                cd_title TEXT,
                track_title TEXT,
                episode TEXT,
                scene TEXT,
                take TEXT,
                tape TEXT,
                cue_number INTEGER,
                sync_point INTEGER,
                release_date TEXT,
                track_year TEXT,
                is_edited INTEGER,
                is_split INTEGER,
                location TEXT,
                group TEXT,
                markers TEXT,
                comments TEXT,
                notes TEXT,
                copyright TEXT,
                coding_history TEXT,
                microphone TEXT,
                mic_perspective TEXT,
                user1 TEXT,
                user2 TEXT,
                user3 TEXT,
                user4 TEXT,
                user5 TEXT,
                user6 TEXT,
                user7 TEXT,
                user8 TEXT,
                
                INDEX idx_md5 (md5),
                INDEX idx_path (path),
                INDEX idx_unique_id (unique_id)
            );
        ";
        
        connection.Execute(sql);
    }
    
    /// <summary>
    /// 添加单条音频记录
    /// </summary>
    /// <param name="meta">音频元数据</param>
    /// <returns>是否添加成功</returns>
    public static bool AddEntry(AudioFileMeta meta)
    {
        try
        {
            using var connection = GetConnection();
            connection.Open();
            
            const string sql = @"
                INSERT INTO audio_files (
                    unique_id, short_id, md5, path, filename, folder, directory,
                    duration, total_samples, bit_depth, channels, sample_rate, type,
                    date_added, original_modification_date, origination_time,
                    bpm, frame_rate, timecode, description, category, subcategory,
                    cat_id, category_full, genre, style, mood, keywords, rating,
                    artist, composer, designer, recordist, publisher, manufacturer,
                    originator, originator_ref, project_name, library, cd_title,
                    track_title, episode, scene, take, tape, cue_number, sync_point,
                    release_date, track_year, is_edited, is_split, location, group,
                    markers, comments, notes, copyright, coding_history, microphone,
                    mic_perspective, user1, user2, user3, user4, user5, user6, user7, user8
                ) VALUES (
                    @UniqueId, @ShortId, @Md5, @Path, @Filename, @Folder, @Directory,
                    @Duration, @TotalSamples, @BitDepth, @Channels, @SampleRate, @Type,
                    @DateAdded, @OriginalModificationDate, @OriginationTime,
                    @Bpm, @FrameRate, @Timecode, @Description, @Category, @Subcategory,
                    @CatId, @CategoryFull, @Genre, @Style, @Mood, @Keywords, @Rating,
                    @Artist, @Composer, @Designer, @Recordist, @Publisher, @Manufacturer,
                    @Originator, @OriginatorRef, @ProjectName, @Library, @CdTitle,
                    @TrackTitle, @Episode, @Scene, @Take, @Tape, @CueNumber, @SyncPoint,
                    @ReleaseDate, @TrackYear, @IsEdited, @IsSplit, @Location, @Group,
                    @Markers, @Comments, @Notes, @Copyright, @CodingHistory, @Microphone,
                    @MicPerspective, @User1, @User2, @User3, @User4, @User5, @User6, @User7, @User8
                );
            ";
            
            connection.Execute(sql, meta);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }
    
    /// <summary>
    /// 批量添加音频记录
    /// </summary>
    /// <param name="entries">音频元数据列表</param>
    /// <returns>成功添加的记录数</returns>
    public static int AddEntries(IEnumerable<AudioFileMeta> entries)
    {
        var count = 0;
        using var connection = GetConnection();
        connection.Open();
        
        using var transaction = connection.BeginTransaction();
        try
        {
            const string sql = @"
                INSERT INTO audio_files (
                    unique_id, short_id, md5, path, filename, folder, directory,
                    duration, total_samples, bit_depth, channels, sample_rate, type,
                    date_added, original_modification_date, origination_time,
                    bpm, frame_rate, timecode, description, category, subcategory,
                    cat_id, category_full, genre, style, mood, keywords, rating,
                    artist, composer, designer, recordist, publisher, manufacturer,
                    originator, originator_ref, project_name, library, cd_title,
                    track_title, episode, scene, take, tape, cue_number, sync_point,
                    release_date, track_year, is_edited, is_split, location, group,
                    markers, comments, notes, copyright, coding_history, microphone,
                    mic_perspective, user1, user2, user3, user4, user5, user6, user7, user8
                ) VALUES (
                    @UniqueId, @ShortId, @Md5, @Path, @Filename, @Folder, @Directory,
                    @Duration, @TotalSamples, @BitDepth, @Channels, @SampleRate, @Type,
                    @DateAdded, @OriginalModificationDate, @OriginationTime,
                    @Bpm, @FrameRate, @Timecode, @Description, @Category, @Subcategory,
                    @CatId, @CategoryFull, @Genre, @Style, @Mood, @Keywords, @Rating,
                    @Artist, @Composer, @Designer, @Recordist, @Publisher, @Manufacturer,
                    @Originator, @OriginatorRef, @ProjectName, @Library, @CdTitle,
                    @TrackTitle, @Episode, @Scene, @Take, @Tape, @CueNumber, @SyncPoint,
                    @ReleaseDate, @TrackYear, @IsEdited, @IsSplit, @Location, @Group,
                    @Markers, @Comments, @Notes, @Copyright, @CodingHistory, @Microphone,
                    @MicPerspective, @User1, @User2, @User3, @User4, @User5, @User6, @User7, @User8
                );
            ";
            
            foreach (var entry in entries)
            {
                connection.Execute(sql, entry, transaction);
                count++;
            }
            
            transaction.Commit();
        }
        catch (Exception)
        {
            transaction.Rollback();
            throw;
        }
        
        return count;
    }
    
    /// <summary>
    /// 检查记录是否已存在
    /// </summary>
    /// <param name="md5">文件 MD5 值</param>
    /// <param name="filePath">文件路径</param>
    /// <returns>是否存在</returns>
    public static bool EntryExists(string md5, string filePath)
    {
        using var connection = GetConnection();
        connection.Open();
        
        const string sql = @"
            SELECT COUNT(*) FROM audio_files 
            WHERE md5 = @Md5 OR path = @Path;
        ";
        
        var count = connection.ExecuteScalar<int>(sql, new { Md5 = md5, Path = filePath });
        return count > 0;
    }
}
