package db

import (
	"database/sql"
	"errors"
)

func (d *DB) GetEmailLogByID(id int64) (*EmailLog, error) {
	row := d.QueryRow(`SELECT id, message_id, timestamp, peer_ip, mail_from, to_address, cc_addresses, bcc_addresses, subject, email_headers, message_body, status, dkim_signed, username, created_at
		FROM esrv_email_logs WHERE id = ?`, id)
	return scanEmailLog(row)
}

func scanEmailLog(row *sql.Row) (*EmailLog, error) {
	var l EmailLog
	var ts, createdAt string
	if err := row.Scan(&l.ID, &l.MessageID, &ts, &l.PeerIP, &l.MailFrom, &l.ToAddress, &l.CcAddresses, &l.BccAddresses, &l.Subject, &l.EmailHeaders, &l.MessageBody, &l.Status, &l.DKIMSigned, &l.Username, &createdAt); err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, nil
		}
		return nil, err
	}
	l.Timestamp, _ = parseTime(ts)
	l.CreatedAt, _ = parseTime(createdAt)
	return &l, nil
}

func (d *DB) ListEmailLogsPage(offset, limit int) ([]EmailLog, error) {
	rows, err := d.Query(`SELECT id, message_id, timestamp, peer_ip, mail_from, to_address, cc_addresses, bcc_addresses, subject, email_headers, message_body, status, dkim_signed, username, created_at
		FROM esrv_email_logs ORDER BY created_at DESC LIMIT ? OFFSET ?`, limit, offset)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var out []EmailLog
	for rows.Next() {
		var l EmailLog
		var ts, createdAt string
		if err := rows.Scan(&l.ID, &l.MessageID, &ts, &l.PeerIP, &l.MailFrom, &l.ToAddress, &l.CcAddresses, &l.BccAddresses, &l.Subject, &l.EmailHeaders, &l.MessageBody, &l.Status, &l.DKIMSigned, &l.Username, &createdAt); err != nil {
			return nil, err
		}
		l.Timestamp, _ = parseTime(ts)
		l.CreatedAt, _ = parseTime(createdAt)
		out = append(out, l)
	}
	return out, rows.Err()
}

func (d *DB) ListAuthLogsPage(offset, limit int) ([]AuthLog, error) {
	rows, err := d.Query(`SELECT id, auth_type, identifier, ip_address, success, message, created_at FROM esrv_auth_logs ORDER BY created_at DESC LIMIT ? OFFSET ?`, limit, offset)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var out []AuthLog
	for rows.Next() {
		var a AuthLog
		var createdAt string
		if err := rows.Scan(&a.ID, &a.AuthType, &a.Identifier, &a.IPAddress, &a.Success, &a.Message, &createdAt); err != nil {
			return nil, err
		}
		a.CreatedAt, _ = parseTime(createdAt)
		out = append(out, a)
	}
	return out, rows.Err()
}

func (d *DB) ListRecentAuthLogs(limit int) ([]AuthLog, error) {
	return d.ListAuthLogsPage(0, limit)
}

func (d *DB) ListRecipientLogsForEmail(emailLogID int64) ([]EmailRecipientLog, error) {
	rows, err := d.Query(`SELECT id, email_log_id, recipient, recipient_type, status, error_code, error_message, server_response FROM esrv_email_recipient_logs WHERE email_log_id = ?`, emailLogID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var out []EmailRecipientLog
	for rows.Next() {
		var r EmailRecipientLog
		if err := rows.Scan(&r.ID, &r.EmailLogID, &r.Recipient, &r.RecipientType, &r.Status, &r.ErrorCode, &r.ErrorMessage, &r.ServerResponse); err != nil {
			return nil, err
		}
		out = append(out, r)
	}
	return out, rows.Err()
}

func (d *DB) ListAttachmentsForEmail(emailLogID int64) ([]EmailAttachment, error) {
	rows, err := d.Query(`SELECT id, email_log_id, filename, content_type, file_path, size, uploaded_at FROM esrv_email_attachments WHERE email_log_id = ?`, emailLogID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var out []EmailAttachment
	for rows.Next() {
		var a EmailAttachment
		var uploadedAt string
		if err := rows.Scan(&a.ID, &a.EmailLogID, &a.Filename, &a.ContentType, &a.FilePath, &a.Size, &uploadedAt); err != nil {
			return nil, err
		}
		a.UploadedAt, _ = parseTime(uploadedAt)
		out = append(out, a)
	}
	return out, rows.Err()
}

func (d *DB) GetAttachmentByID(id int64) (*EmailAttachment, error) {
	row := d.QueryRow(`SELECT id, email_log_id, filename, content_type, file_path, size, uploaded_at FROM esrv_email_attachments WHERE id = ?`, id)
	var a EmailAttachment
	var uploadedAt string
	if err := row.Scan(&a.ID, &a.EmailLogID, &a.Filename, &a.ContentType, &a.FilePath, &a.Size, &uploadedAt); err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, nil
		}
		return nil, err
	}
	a.UploadedAt, _ = parseTime(uploadedAt)
	return &a, nil
}

func (d *DB) RemoveAttachment(id int64) error {
	_, err := d.Exec(`DELETE FROM esrv_email_attachments WHERE id = ?`, id)
	return err
}
