import { Response } from 'express';
import { AuthenticatedRequest } from '../types/auth';
import { userMailAccountService } from '../services/userMailAccountService';
import { userMailImapService } from '../services/userMailImapService';
import { userMailSmtpService } from '../services/userMailSmtpService';
import { encryptionService } from '../services/encryptionService';
import { imapConnectionPool } from '../services/imapConnectionPool';
import { mailCache } from '../services/mailCache';

class UserMailController {
  async listAccounts(req: AuthenticatedRequest, res: Response) {
    try {
      const userId = (req as any).user?.userId;
      if (!userId) return res.status(401).json({ success: false, message: '인증 필요' });

      const protocol = req.query.protocol as string | undefined;
      const accounts = await userMailAccountService.getAccountsByUserId(userId, protocol);
      // 비밀번호 제거 후 반환
      const safe = accounts.map(({ password, ...rest }) => rest);
      res.json({ success: true, data: safe });
    } catch (error) {
      res.status(500).json({ success: false, message: error instanceof Error ? error.message : '서버 오류' });
    }
  }

  async createAccount(req: AuthenticatedRequest, res: Response) {
    try {
      const userId = (req as any).user?.userId;
      if (!userId) return res.status(401).json({ success: false, message: '인증 필요' });

      // 저장 전 연결 테스트 (임시 account 객체 사용, 평문 비밀번호를 암호화해서 전달)
      const tempAccount = { ...req.body, id: 0, userId, status: 'active', password: encryptionService.encrypt(req.body.password) };
      const service = userMailImapService;
      const testResult = await service.testConnection(tempAccount);
      if (!testResult.success) {
        return res.status(400).json({ success: false, message: `연결 테스트 실패: ${testResult.message}` });
      }

      const account = await userMailAccountService.createAccount(userId, req.body);
      const { password, ...safe } = account;
      res.status(201).json({ success: true, data: safe });
    } catch (error) {
      res.status(500).json({ success: false, message: error instanceof Error ? error.message : '서버 오류' });
    }
  }

  async updateAccount(req: AuthenticatedRequest, res: Response) {
    try {
      const userId = (req as any).user?.userId;
      if (!userId) return res.status(401).json({ success: false, message: '인증 필요' });

      const accountId = parseInt(req.params.accountId);

      // 비밀번호 변경이 포함된 경우 연결 테스트
      if (req.body.password) {
        const existing = await userMailAccountService.getAccountById(accountId, userId);
        if (!existing) return res.status(404).json({ success: false, message: '계정을 찾을 수 없습니다.' });

        const tempAccount = { ...existing, ...req.body, password: encryptionService.encrypt(req.body.password) };
        const service = userMailImapService;
        const testResult = await service.testConnection(tempAccount);
        if (!testResult.success) {
          return res.status(400).json({ success: false, message: `연결 테스트 실패: ${testResult.message}` });
        }
      }

      const account = await userMailAccountService.updateAccount(accountId, userId, req.body);
      if (!account) return res.status(404).json({ success: false, message: '계정을 찾을 수 없습니다.' });

      imapConnectionPool.destroyByAccount(accountId);
      mailCache.invalidateByPrefix(`mailList:${accountId}:`);
      mailCache.invalidateByPrefix(`mailDetail:${accountId}:`);

      const { password, ...safe } = account;
      res.json({ success: true, data: safe });
    } catch (error) {
      res.status(500).json({ success: false, message: error instanceof Error ? error.message : '서버 오류' });
    }
  }

  async deleteAccount(req: AuthenticatedRequest, res: Response) {
    try {
      const userId = (req as any).user?.userId;
      if (!userId) return res.status(401).json({ success: false, message: '인증 필요' });

      const accountId = parseInt(req.params.accountId);
      const deleted = await userMailAccountService.deleteAccount(accountId, userId);
      if (!deleted) return res.status(404).json({ success: false, message: '계정을 찾을 수 없습니다.' });

      imapConnectionPool.destroyByAccount(accountId);
      mailCache.invalidateByPrefix(`mailList:${accountId}:`);
      mailCache.invalidateByPrefix(`mailDetail:${accountId}:`);

      res.json({ success: true, message: '계정이 삭제되었습니다.' });
    } catch (error) {
      res.status(500).json({ success: false, message: error instanceof Error ? error.message : '서버 오류' });
    }
  }

  async testConnectionDirect(req: AuthenticatedRequest, res: Response) {
    try {
      const userId = (req as any).user?.userId;
      if (!userId) return res.status(401).json({ success: false, message: '인증 필요' });

      const { protocol, host, port, useTls, username, password } = req.body;
      if (!protocol || !host || !port || !username || !password) {
        return res.status(400).json({ success: false, message: '필수 항목 누락' });
      }

      const tempAccount = {
        id: 0, userId, displayName: '', email: '', protocol, host, port,
        useTls: useTls ?? true, username, status: 'active',
        password: encryptionService.encrypt(password),
        createdAt: new Date(), updatedAt: new Date(),
      };

      const service = userMailImapService;
      const result = await service.testConnection(tempAccount);
      res.json({ success: true, data: result });
    } catch (error) {
      res.status(500).json({ success: false, message: error instanceof Error ? error.message : '서버 오류' });
    }
  }

  async testConnection(req: AuthenticatedRequest, res: Response) {
    try {
      const userId = (req as any).user?.userId;
      if (!userId) return res.status(401).json({ success: false, message: '인증 필요' });

      const accountId = parseInt(req.params.accountId);
      const account = await userMailAccountService.getAccountById(accountId, userId);
      if (!account) return res.status(404).json({ success: false, message: '계정을 찾을 수 없습니다.' });

      const service = userMailImapService;
      const result = await service.testConnection(account);
      res.json({ success: true, data: result });
    } catch (error) {
      res.status(500).json({ success: false, message: error instanceof Error ? error.message : '서버 오류' });
    }
  }

  async listMails(req: AuthenticatedRequest, res: Response) {
    try {
      const userId = (req as any).user?.userId;
      if (!userId) return res.status(401).json({ success: false, message: '인증 필요' });

      const accountId = parseInt(req.params.accountId);
      const account = await userMailAccountService.getAccountById(accountId, userId);
      if (!account) return res.status(404).json({ success: false, message: '계정을 찾을 수 없습니다.' });

      const limit = parseInt(req.query.limit as string) || 50;
      const service = userMailImapService;
      const mails = await service.fetchMailList(account, limit);
      res.json({ success: true, data: mails });
    } catch (error) {
      res.status(500).json({ success: false, message: error instanceof Error ? error.message : '서버 오류' });
    }
  }

  async streamMails(req: AuthenticatedRequest, res: Response) {
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
    res.setHeader('X-Accel-Buffering', 'no');
    res.flushHeaders();

    const userId = (req as any).user?.userId;
    const accountId = parseInt(req.params.accountId);
    const limit = parseInt(req.query.limit as string) || 20;
    const before = req.query.before ? parseInt(req.query.before as string) : null;

    const account = await userMailAccountService.getAccountById(accountId, userId);
    if (!account) {
      res.write(`event: error\ndata: ${JSON.stringify({ message: '계정을 찾을 수 없습니다.' })}\n\n`);
      return res.end();
    }

    let ended = false;
    req.on('close', () => { ended = true; });

    await userMailImapService.fetchMailListStream(
      account, limit, before,
      (mail) => {
        if (!ended) res.write(`data: ${JSON.stringify(mail)}\n\n`);
      },
      () => {
        if (!ended) {
          res.write(`event: done\ndata: {}\n\n`);
          res.end();
        }
      },
      (err) => {
        if (!ended) {
          res.write(`event: error\ndata: ${JSON.stringify({ message: err.message })}\n\n`);
          res.end();
        }
      }
    );
  }

  async getMailDetail(req: AuthenticatedRequest, res: Response) {
    try {
      const userId = (req as any).user?.userId;
      if (!userId) return res.status(401).json({ success: false, message: '인증 필요' });

      const accountId = parseInt(req.params.accountId);
      const account = await userMailAccountService.getAccountById(accountId, userId);
      if (!account) return res.status(404).json({ success: false, message: '계정을 찾을 수 없습니다.' });

      const seqno = parseInt(req.params.seqno);
      const service = userMailImapService;
      const detail = await service.getMailDetail(account, seqno);
      if (!detail) return res.status(404).json({ success: false, message: '메일을 찾을 수 없습니다.' });

      res.json({ success: true, data: detail });
    } catch (error) {
      res.status(500).json({ success: false, message: error instanceof Error ? error.message : '서버 오류' });
    }
  }

  async markAsRead(req: AuthenticatedRequest, res: Response) {
    try {
      const userId = (req as any).user?.userId;
      if (!userId) return res.status(401).json({ success: false, message: '인증 필요' });

      const accountId = parseInt(req.params.accountId);
      const account = await userMailAccountService.getAccountById(accountId, userId);
      if (!account) return res.status(404).json({ success: false, message: '계정을 찾을 수 없습니다.' });

      const seqno = parseInt(req.params.seqno);
      const service = userMailImapService;
      const result = await service.markAsRead(account, seqno);
      res.json({ success: true, data: result });
    } catch (error) {
      res.status(500).json({ success: false, message: error instanceof Error ? error.message : '서버 오류' });
    }
  }

  async deleteMail(req: AuthenticatedRequest, res: Response) {
    try {
      const userId = (req as any).user?.userId;
      if (!userId) return res.status(401).json({ success: false, message: '인증 필요' });

      const accountId = parseInt(req.params.accountId);
      const account = await userMailAccountService.getAccountById(accountId, userId);
      if (!account) return res.status(404).json({ success: false, message: '계정을 찾을 수 없습니다.' });

      const seqno = parseInt(req.params.seqno);
      const service = userMailImapService;
      const result = await service.deleteMail(account, seqno);
      res.json({ success: true, data: result });
    } catch (error) {
      res.status(500).json({ success: false, message: error instanceof Error ? error.message : '서버 오류' });
    }
  }

  async listFolders(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const accountId = parseInt(req.params.accountId);
      const account = await userMailAccountService.getAccountById(accountId, (req as any).user!.userId);
      if (!account) { res.status(404).json({ success: false, message: '계정 없음' }); return; }
      const folders = await userMailImapService.listFolders(account);
      res.json({ success: true, data: folders });
    } catch (err) {
      res.status(500).json({ success: false, message: err instanceof Error ? err.message : '오류' });
    }
  }

  async streamFolderMails(req: AuthenticatedRequest, res: Response): Promise<void> {
    const accountId = parseInt(req.params.accountId);
    const folder = decodeURIComponent(req.params.folder);
    const limit = parseInt(req.query.limit as string) || 20;
    const before = req.query.before ? parseInt(req.query.before as string) : null;

    const account = await userMailAccountService.getAccountById(accountId, (req as any).user!.userId);
    if (!account) { res.status(404).json({ success: false, message: '계정 없음' }); return; }

    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
    res.flushHeaders();

    await userMailImapService.streamMailsByFolder(
      account, folder, limit, before,
      (mail) => {
        res.write(`event: message\ndata: ${JSON.stringify(mail)}\n\n`);
      },
      () => {
        res.write(`event: done\ndata: {}\n\n`);
        res.end();
      },
      (err) => {
        res.write(`event: error\ndata: ${JSON.stringify({ message: err.message })}\n\n`);
        res.end();
      }
    );
  }

  async moveMail(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const accountId = parseInt(req.params.accountId);
      const seqno = parseInt(req.params.seqno);
      const { targetFolder } = req.body;
      if (!targetFolder) { res.status(400).json({ success: false, message: 'targetFolder 필요' }); return; }
      const account = await userMailAccountService.getAccountById(accountId, (req as any).user!.userId);
      if (!account) { res.status(404).json({ success: false, message: '계정 없음' }); return; }
      const result = await userMailImapService.moveMail(account, seqno, targetFolder);
      res.json(result);
    } catch (err) {
      res.status(500).json({ success: false, message: err instanceof Error ? err.message : '오류' });
    }
  }

  async getAttachments(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const accountId = parseInt(req.params.accountId);
      const seqno = parseInt(req.params.seqno);
      const account = await userMailAccountService.getAccountById(accountId, (req as any).user!.userId);
      if (!account) { res.status(404).json({ success: false, message: '계정 없음' }); return; }
      const folder = (req.query.folder as string) || 'INBOX';
      const attachments = await userMailImapService.getAttachmentList(account, seqno, folder);
      res.json({ success: true, data: attachments });
    } catch (err) {
      res.status(500).json({ success: false, message: err instanceof Error ? err.message : '오류' });
    }
  }

  async downloadAttachment(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const accountId = parseInt(req.params.accountId);
      const seqno = parseInt(req.params.seqno);
      const partId = decodeURIComponent(req.params.partId);
      const account = await userMailAccountService.getAccountById(accountId, (req as any).user!.userId);
      if (!account) { res.status(404).json({ success: false, message: '계정 없음' }); return; }
      const folder = (req.query.folder as string) || 'INBOX';
      const filenameHint = (req.params.filename as string | undefined) || (req.query.filename as string | undefined);
      await userMailImapService.downloadAttachment(account, seqno, partId, res, folder, filenameHint);
    } catch (err) {
      if (!res.headersSent) {
        res.status(500).json({ success: false, message: err instanceof Error ? err.message : '오류' });
      }
    }
  }

  async sendMail(req: AuthenticatedRequest, res: Response): Promise<void> {
    try {
      const accountId = parseInt(req.params.accountId);
      const account = await userMailAccountService.getAccountById(accountId, (req as any).user!.userId);
      if (!account) { res.status(404).json({ success: false, message: '계정 없음' }); return; }
      const result = await userMailSmtpService.sendMail(account, req.body);
      res.json(result);
    } catch (err) {
      res.status(500).json({ success: false, message: err instanceof Error ? err.message : '오류' });
    }
  }
}

export const userMailController = new UserMailController();
