using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Dapper;
using QuantEngine.Core.Interfaces;
using QuantEngine.Core.Models;
using QuantEngine.Infrastructure.Data;

namespace QuantEngine.Infrastructure.Repositories
{
    public class WorkspaceRepository : IWorkspaceRepository
    {
        private readonly IDbConnectionFactory _connectionFactory;

        public WorkspaceRepository(IDbConnectionFactory connectionFactory)
        {
            _connectionFactory = connectionFactory;
        }

        // Accounts
        public async Task<IEnumerable<WorkspaceAccount>> GetAccountsAsync()
        {
            using var conn = _connectionFactory.CreateConnection();
            return await conn.QueryAsync<WorkspaceAccount>(@"
                SELECT ordinal, username as Username, password_hash as PasswordHash, role as Role,
                       is_active as IsActive, created_at as CreatedAt, updated_at as UpdatedAt
                FROM quantengine.workspace_account
                ORDER BY ordinal ASC"
            );
        }

        public async Task<WorkspaceAccount?> GetAccountByUsernameAsync(string username)
        {
            using var conn = _connectionFactory.CreateConnection();
            return await conn.QueryFirstOrDefaultAsync<WorkspaceAccount>(@"
                SELECT ordinal, username as Username, password_hash as PasswordHash, role as Role,
                       is_active as IsActive, created_at as CreatedAt, updated_at as UpdatedAt
                FROM quantengine.workspace_account
                WHERE username = @Username",
                new { Username = username }
            );
        }

        public async Task<bool> UpsertAccountAsync(WorkspaceAccount account)
        {
            using var conn = _connectionFactory.CreateConnection();
            var affected = await conn.ExecuteAsync(@"
                INSERT INTO quantengine.workspace_account (ordinal, username, password_hash, role, is_active, created_at, updated_at)
                VALUES (@Ordinal, @Username, @PasswordHash, @Role, @IsActive, @CreatedAt, @UpdatedAt)
                ON CONFLICT (username) DO UPDATE SET
                    ordinal = EXCLUDED.ordinal,
                    password_hash = EXCLUDED.password_hash,
                    role = EXCLUDED.role,
                    is_active = EXCLUDED.is_active,
                    updated_at = EXCLUDED.updated_at",
                account
            );
            return affected > 0;
        }

        public async Task<WorkspaceSession?> GetSessionByTokenHashAsync(string tokenHash)
        {
            using var conn = _connectionFactory.CreateConnection();
            return await conn.QueryFirstOrDefaultAsync<WorkspaceSession>(@"
                SELECT session_token_hash as SessionTokenHash, username as Username, role as Role,
                       created_at as CreatedAt, expires_at as ExpiresAt, revoked_at as RevokedAt
                FROM quantengine.workspace_session
                WHERE session_token_hash = @TokenHash",
                new { TokenHash = tokenHash }
            );
        }

        public async Task<bool> UpsertSessionAsync(WorkspaceSession session)
        {
            using var conn = _connectionFactory.CreateConnection();
            var affected = await conn.ExecuteAsync(@"
                INSERT INTO quantengine.workspace_session
                    (session_token_hash, username, role, created_at, expires_at, revoked_at)
                VALUES
                    (@SessionTokenHash, @Username, @Role, @CreatedAt, @ExpiresAt, @RevokedAt)
                ON CONFLICT (session_token_hash) DO UPDATE SET
                    username = EXCLUDED.username,
                    role = EXCLUDED.role,
                    expires_at = EXCLUDED.expires_at,
                    revoked_at = EXCLUDED.revoked_at",
                session
            );
            return affected > 0;
        }

        public async Task<bool> RevokeSessionAsync(string tokenHash, string revokedAt)
        {
            using var conn = _connectionFactory.CreateConnection();
            var affected = await conn.ExecuteAsync(@"
                UPDATE quantengine.workspace_session
                SET revoked_at = @RevokedAt
                WHERE session_token_hash = @TokenHash",
                new { TokenHash = tokenHash, RevokedAt = revokedAt }
            );
            return affected > 0;
        }

        // Settings
        public async Task<IEnumerable<Setting>> GetSettingsAsync()
        {
            using var conn = _connectionFactory.CreateConnection();
            return await conn.QueryAsync<Setting>(
                "SELECT ordinal, key, value_json as ValueJson, note, updated_at as UpdatedAt FROM quantengine.settings ORDER BY ordinal ASC"
            );
        }

        public async Task<Setting?> GetSettingByKeyAsync(string key)
        {
            using var conn = _connectionFactory.CreateConnection();
            return await conn.QueryFirstOrDefaultAsync<Setting>(
                "SELECT ordinal, key, value_json as ValueJson, note, updated_at as UpdatedAt FROM quantengine.settings WHERE key = @Key",
                new { Key = key }
            );
        }

        public async Task<bool> UpsertSettingAsync(Setting setting)
        {
            using var conn = _connectionFactory.CreateConnection();
            var affected = await conn.ExecuteAsync(@"
                INSERT INTO quantengine.settings (ordinal, key, value_json, note, updated_at)
                VALUES (@Ordinal, @Key, @ValueJson, @Note, @UpdatedAt)
                ON CONFLICT (key) DO UPDATE SET
                    ordinal = EXCLUDED.ordinal,
                    value_json = EXCLUDED.value_json,
                    note = EXCLUDED.note,
                    updated_at = EXCLUDED.updated_at",
                setting
            );
            return affected > 0;
        }

        public async Task<bool> DeleteSettingAsync(string key)
        {
            using var conn = _connectionFactory.CreateConnection();
            var affected = await conn.ExecuteAsync(
                "DELETE FROM quantengine.settings WHERE key = @Key",
                new { Key = key }
            );
            return affected > 0;
        }

        // AccountSnapshot
        public async Task<IEnumerable<AccountSnapshot>> GetAccountSnapshotsAsync()
        {
            using var conn = _connectionFactory.CreateConnection();
            return await conn.QueryAsync<AccountSnapshot>(@"
                SELECT ordinal, row_json as RowJson, captured_at as CapturedAt, account, account_type as AccountType, 
                       ticker, name, parse_status as ParseStatus, user_confirmed as UserConfirmed, updated_at as UpdatedAt 
                FROM quantengine.account_snapshot 
                ORDER BY ordinal ASC"
            );
        }

        public async Task<bool> InsertAccountSnapshotsAsync(IEnumerable<AccountSnapshot> snapshots)
        {
            using var conn = _connectionFactory.CreateConnection();
            conn.Open();
            using var tx = conn.BeginTransaction();
            try
            {
                foreach (var snapshot in snapshots)
                {
                    await conn.ExecuteAsync(@"
                        INSERT INTO quantengine.account_snapshot (ordinal, row_json, captured_at, account, account_type, ticker, name, parse_status, user_confirmed, updated_at)
                        VALUES (@Ordinal, @RowJson, @CapturedAt, @Account, @AccountType, @Ticker, @Name, @ParseStatus, @UserConfirmed, @UpdatedAt)",
                        snapshot,
                        tx
                    );
                }
                tx.Commit();
                return true;
            }
            catch
            {
                tx.Rollback();
                throw;
            }
        }

        public async Task<bool> ClearAccountSnapshotsAsync()
        {
            using var conn = _connectionFactory.CreateConnection();
            var affected = await conn.ExecuteAsync("DELETE FROM quantengine.account_snapshot");
            return affected >= 0;
        }

        // WorkspaceApproval
        public async Task<IEnumerable<WorkspaceApproval>> GetApprovalsAsync()
        {
            using var conn = _connectionFactory.CreateConnection();
            return await conn.QueryAsync<WorkspaceApproval>(@"
                SELECT domain, target_ref as TargetRef, status, approved_by as ApprovedBy, 
                       approved_at as ApprovedAt, note, updated_at as UpdatedAt 
                FROM quantengine.workspace_approval_v2"
            );
        }

        public async Task<WorkspaceApproval?> GetApprovalAsync(string domain, string targetRef)
        {
            using var conn = _connectionFactory.CreateConnection();
            return await conn.QueryFirstOrDefaultAsync<WorkspaceApproval>(@"
                SELECT domain, target_ref as TargetRef, status, approved_by as ApprovedBy, 
                       approved_at as ApprovedAt, note, updated_at as UpdatedAt 
                FROM quantengine.workspace_approval_v2 
                WHERE domain = @Domain AND target_ref = @TargetRef",
                new { Domain = domain, TargetRef = targetRef }
            );
        }

        public async Task<bool> UpsertApprovalAsync(WorkspaceApproval approval)
        {
            using var conn = _connectionFactory.CreateConnection();
            var affected = await conn.ExecuteAsync(@"
                INSERT INTO quantengine.workspace_approval_v2 (domain, target_ref, status, approved_by, approved_at, note, updated_at)
                VALUES (@Domain, @TargetRef, @Status, @ApprovedBy, @ApprovedAt, @Note, @UpdatedAt)
                ON CONFLICT (domain, target_ref) DO UPDATE SET
                    status = EXCLUDED.status,
                    approved_by = EXCLUDED.approved_by,
                    approved_at = EXCLUDED.approved_at,
                    note = EXCLUDED.note,
                    updated_at = EXCLUDED.updated_at",
                approval
            );
            return affected > 0;
        }

        // WorkspaceLock
        public async Task<IEnumerable<WorkspaceLock>> GetLocksAsync()
        {
            using var conn = _connectionFactory.CreateConnection();
            return await conn.QueryAsync<WorkspaceLock>(@"
                SELECT domain, target_ref as TargetRef, locked_by as LockedBy, reason, locked_at as LockedAt 
                FROM quantengine.workspace_lock"
            );
        }

        public async Task<WorkspaceLock?> GetLockAsync(string domain, string targetRef)
        {
            using var conn = _connectionFactory.CreateConnection();
            return await conn.QueryFirstOrDefaultAsync<WorkspaceLock>(@"
                SELECT domain, target_ref as TargetRef, locked_by as LockedBy, reason, locked_at as LockedAt 
                FROM quantengine.workspace_lock 
                WHERE domain = @Domain AND target_ref = @TargetRef",
                new { Domain = domain, TargetRef = targetRef }
            );
        }

        public async Task<bool> AcquireLockAsync(WorkspaceLock @lock)
        {
            using var conn = _connectionFactory.CreateConnection();
            var affected = await conn.ExecuteAsync(@"
                INSERT INTO quantengine.workspace_lock (domain, target_ref, locked_by, reason, locked_at)
                VALUES (@Domain, @TargetRef, @LockedBy, @Reason, @LockedAt)
                ON CONFLICT (domain, target_ref) DO NOTHING",
                @lock
            );
            return affected > 0;
        }

        public async Task<bool> ReleaseLockAsync(string domain, string targetRef)
        {
            using var conn = _connectionFactory.CreateConnection();
            var affected = await conn.ExecuteAsync(
                "DELETE FROM quantengine.workspace_lock WHERE domain = @Domain AND target_ref = @TargetRef",
                new { Domain = domain, TargetRef = targetRef }
            );
            return affected > 0;
        }
    }
}
