import { localDataSource } from '../LocalDataSource';
import { CachedMessage } from '../types';
import type { ILocalDataSource } from '@/data/datasources/interfaces';

export interface IMessageRepository {
  saveMessage(message: CachedMessage): Promise<void>;
  saveMessagesBatch(messages: CachedMessage[]): Promise<void>;
  getByConversation(conversationId: string, limit?: number): Promise<CachedMessage[]>;
  getMaxSeq(conversationId: string): Promise<number>;
  getMinSeq(conversationId: string): Promise<number>;
  getBeforeSeq(conversationId: string, beforeSeq: number, limit?: number): Promise<CachedMessage[]>;
  getCount(conversationId: string): Promise<number>;
  getCountBeforeSeq(conversationId: string, beforeSeq: number): Promise<number>;
  markAsRead(messageId: string): Promise<void>;
  markConversationAsRead(conversationId: string): Promise<void>;
  delete(messageId: string): Promise<void>;
  updateStatus(messageId: string, status: string, clearContent?: boolean): Promise<void>;
  clearConversation(conversationId: string): Promise<void>;
  search(keyword: string): Promise<CachedMessage[]>;
  getStats(): Promise<{ totalMessages: number; totalConversations: number }>;
  getLastMessageByConversation(conversationId: string): Promise<CachedMessage | null>;
}

export class MessageRepository implements IMessageRepository {
  constructor(private dataSource: ILocalDataSource = localDataSource) {}

  async saveMessage(message: CachedMessage): Promise<void> {
    await this.dataSource.enqueueWrite(async () => {
      await this.dataSource.run(
        `INSERT OR REPLACE INTO messages (id, conversationId, senderId, content, type, isRead, createdAt, seq, status, segments)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [message.id, message.conversationId, message.senderId, message.content || '',
         message.type || 'text', message.isRead ? 1 : 0, message.createdAt,
         message.seq || 0, message.status || 'normal',
         message.segments ? JSON.stringify(message.segments) : null]
      );
    });
  }

  async saveMessagesBatch(messages: CachedMessage[]): Promise<void> {
    if (!messages?.length) return;
    await this.dataSource.enqueueWrite(async () => {
      for (const msg of messages) {
        await this.dataSource.run(
          `INSERT OR REPLACE INTO messages (id, conversationId, senderId, content, type, isRead, createdAt, seq, status, segments)
           VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
          [msg.id, msg.conversationId, msg.senderId, msg.content || '',
           msg.type || 'text', msg.isRead ? 1 : 0, msg.createdAt,
           msg.seq || 0, msg.status || 'normal',
           msg.segments ? JSON.stringify(msg.segments) : null]
        );
      }
    });
  }

  async getByConversation(conversationId: string, limit: number = 20): Promise<CachedMessage[]> {
    const rows = await this.dataSource.query<any>(
      `SELECT * FROM messages WHERE conversationId = ? ORDER BY seq DESC LIMIT ?`,
      [conversationId, limit]
    );
    return rows.reverse().map(r => ({
      ...r, isRead: r.isRead === 1, segments: r.segments ? JSON.parse(r.segments) : undefined
    }));
  }

  async getMaxSeq(conversationId: string): Promise<number> {
    const r = await this.dataSource.getFirst<{ maxSeq: number }>(
      `SELECT MAX(seq) as maxSeq FROM messages WHERE conversationId = ?`, [conversationId]
    );
    return r?.maxSeq || 0;
  }

  async getMinSeq(conversationId: string): Promise<number> {
    const r = await this.dataSource.getFirst<{ minSeq: number }>(
      `SELECT MIN(seq) as minSeq FROM messages WHERE conversationId = ?`, [conversationId]
    );
    return r?.minSeq || 0;
  }

  async getBeforeSeq(conversationId: string, beforeSeq: number, limit: number = 20): Promise<CachedMessage[]> {
    const rows = await this.dataSource.query<any>(
      `SELECT * FROM messages WHERE conversationId = ? AND seq < ? ORDER BY seq DESC LIMIT ?`,
      [conversationId, beforeSeq, limit]
    );
    return rows.map(r => ({ ...r, isRead: r.isRead === 1, segments: r.segments ? JSON.parse(r.segments) : undefined })).reverse();
  }

  async getCount(conversationId: string): Promise<number> {
    const r = await this.dataSource.getFirst<{ count: number }>(
      `SELECT COUNT(*) as count FROM messages WHERE conversationId = ?`, [conversationId]
    );
    return r?.count || 0;
  }

  async getCountBeforeSeq(conversationId: string, beforeSeq: number): Promise<number> {
    const r = await this.dataSource.getFirst<{ count: number }>(
      `SELECT COUNT(*) as count FROM messages WHERE conversationId = ? AND seq < ?`, [conversationId, beforeSeq]
    );
    return r?.count || 0;
  }

  async markAsRead(messageId: string): Promise<void> {
    await this.dataSource.enqueueWrite(async () => {
      await this.dataSource.run(`UPDATE messages SET isRead = 1 WHERE id = ?`, [messageId]);
    });
  }

  async markConversationAsRead(conversationId: string): Promise<void> {
    await this.dataSource.enqueueWrite(async () => {
      await this.dataSource.run(`UPDATE messages SET isRead = 1 WHERE conversationId = ?`, [conversationId]);
    });
  }

  async delete(messageId: string): Promise<void> {
    await this.dataSource.enqueueWrite(async () => {
      await this.dataSource.run(`DELETE FROM messages WHERE id = ?`, [messageId]);
    });
  }

  async updateStatus(messageId: string, status: string, clearContent: boolean = false): Promise<void> {
    await this.dataSource.enqueueWrite(async () => {
      if (clearContent) {
        await this.dataSource.run(
          `UPDATE messages SET status = ?, content = '', segments = '[]' WHERE id = ?`,
          [status, messageId]
        );
      } else {
        await this.dataSource.run(`UPDATE messages SET status = ? WHERE id = ?`, [status, messageId]);
      }
    });
  }

  async clearConversation(conversationId: string): Promise<void> {
    await this.dataSource.enqueueWrite(async () => {
      await this.dataSource.run(`DELETE FROM messages WHERE conversationId = ?`, [conversationId]);
    });
  }

  async search(keyword: string): Promise<CachedMessage[]> {
    const rows = await this.dataSource.query<any>(
      `SELECT * FROM messages WHERE content LIKE ? ORDER BY createdAt DESC LIMIT 50`, [`%${keyword}%`]
    );
    return rows.map(r => ({ ...r, isRead: r.isRead === 1, segments: r.segments ? JSON.parse(r.segments) : undefined }));
  }

  async getStats(): Promise<{ totalMessages: number; totalConversations: number }> {
    const msgCount = await this.dataSource.getFirst<{ count: number }>(`SELECT COUNT(*) as count FROM messages`);
    const convCount = await this.dataSource.getFirst<{ count: number }>(`SELECT COUNT(*) as count FROM conversations`);
    return { totalMessages: msgCount?.count || 0, totalConversations: convCount?.count || 0 };
  }

  async getLastMessageByConversation(conversationId: string): Promise<CachedMessage | null> {
    const r = await this.dataSource.getFirst<any>(
      `SELECT * FROM messages WHERE conversationId = ? AND status != 'deleted' ORDER BY seq DESC LIMIT 1`,
      [conversationId]
    );
    if (!r) return null;
    return { ...r, isRead: r.isRead === 1, segments: r.segments ? JSON.parse(r.segments) : undefined };
  }
}

export const messageRepository = new MessageRepository();