package filesystem

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"sync"
	"time"
)

// AuditOperation 审计操作类型
type AuditOperation string

const (
	OperationRead     AuditOperation = "read"     // 读取文件
	OperationWrite    AuditOperation = "write"    // 写入文件
	OperationDelete   AuditOperation = "delete"   // 删除文件
	OperationCreate   AuditOperation = "create"   // 创建目录
	OperationRename   AuditOperation = "rename"   // 重命名
	OperationMove     AuditOperation = "move"     // 移动
	OperationList     AuditOperation = "list"     // 列出目录
	OperationDownload AuditOperation = "download" // 下载
)

// AuditLogEntry 审计日志条目
type AuditLogEntry struct {
	Timestamp   time.Time      `json:"timestamp"`   // 操作时间
	Operation   AuditOperation `json:"operation"`   // 操作类型
	Path        string         `json:"path"`        // 文件路径
	OldPath     string         `json:"old_path,omitempty"`     // 原路径（重命名/移动）
	Size        int64          `json:"size,omitempty"`        // 文件大小
	IsDirectory bool           `json:"is_directory"` // 是否为目录
	Success     bool           `json:"success"`     // 操作是否成功
	Error       string         `json:"error,omitempty"`       // 错误信息
	UserAgent   string         `json:"user_agent,omitempty"` // 用户代理
	IPAddress   string         `json:"ip_address,omitempty"` // IP地址
}

// AuditLogger 审计日志记录器
type AuditLogger struct {
	logFile  *os.File
	logPath  string
	mu       sync.Mutex
	buffer   []AuditLogEntry
	bufferSize int
	stopChan chan struct{}
}

// NewAuditLogger 创建审计日志记录器
func NewAuditLogger(logDir string) (*AuditLogger, error) {
	// 创建日志目录
	if err := os.MkdirAll(logDir, 0755); err != nil {
		return nil, fmt.Errorf("创建日志目录失败: %v", err)
	}

	// 生成日志文件名（按日期）
	timestamp := time.Now().Format("2006-01-02")
	logPath := filepath.Join(logDir, fmt.Sprintf("audit_%s.log", timestamp))

	// 打开日志文件（追加模式）
	logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		return nil, fmt.Errorf("打开日志文件失败: %v", err)
	}

	logger := &AuditLogger{
		logFile:    logFile,
		logPath:    logPath,
		buffer:     make([]AuditLogEntry, 0, 100),
		bufferSize: 100, // 缓冲100条记录后批量写入
		stopChan:   make(chan struct{}),
	}

	// 启动后台协程，定期刷新缓冲区
	go logger.backgroundFlush()

	return logger, nil
}

// Log 记录操作日志
func (a *AuditLogger) Log(entry AuditLogEntry) error {
	// 设置时间戳
	if entry.Timestamp.IsZero() {
		entry.Timestamp = time.Now()
	}

	a.mu.Lock()
	defer a.mu.Unlock()

	// 添加到缓冲区
	a.buffer = append(a.buffer, entry)

	// 如果缓冲区满了，立即写入
	if len(a.buffer) >= a.bufferSize {
		if err := a.flush(); err != nil {
			return err
		}
	}

	return nil
}

// LogDelete 记录删除操作（便捷方法）
func (a *AuditLogger) LogDelete(path string, isDir bool, size int64, err error) {
	entry := AuditLogEntry{
		Timestamp:   time.Now(),
		Operation:   OperationDelete,
		Path:        path,
		Size:        size,
		IsDirectory: isDir,
		Success:     err == nil,
	}

	if err != nil {
		entry.Error = err.Error()
	}

	_ = a.Log(entry)
}

// LogWrite 记录写入操作（便捷方法）
func (a *AuditLogger) LogWrite(path string, size int64, err error) {
	entry := AuditLogEntry{
		Timestamp:   time.Now(),
		Operation:   OperationWrite,
		Path:        path,
		Size:        size,
		IsDirectory: false,
		Success:     err == nil,
	}

	if err != nil {
		entry.Error = err.Error()
	}

	_ = a.Log(entry)
}

// LogRead 记录读取操作（便捷方法）
func (a *AuditLogger) LogRead(path string, size int64, err error) {
	entry := AuditLogEntry{
		Timestamp:   time.Now(),
		Operation:   OperationRead,
		Path:        path,
		Size:        size,
		IsDirectory: false,
		Success:     err == nil,
	}

	if err != nil {
		entry.Error = err.Error()
	}

	_ = a.Log(entry)
}

// flush 将缓冲区写入文件
func (a *AuditLogger) flush() error {
	if len(a.buffer) == 0 {
		return nil
	}

	// 序列化所有条目为JSON（每行一个）
	for _, entry := range a.buffer {
		data, err := json.Marshal(entry)
		if err != nil {
			continue // 序列化失败，跳过该条目
		}
		if _, err := a.logFile.Write(append(data, '\n')); err != nil {
			return err
		}
	}

	// 刷新到磁盘
	if err := a.logFile.Sync(); err != nil {
		return err
	}

	// 清空缓冲区
	a.buffer = a.buffer[:0]

	return nil
}

// backgroundFlush 后台协程，定期刷新缓冲区
func (a *AuditLogger) backgroundFlush() {
	ticker := time.NewTicker(5 * time.Second) // 每5秒刷新一次
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			a.mu.Lock()
			_ = a.flush()
			a.mu.Unlock()
		case <-a.stopChan:
			// 停止前刷新一次
			a.mu.Lock()
			_ = a.flush()
			a.mu.Unlock()
			return
		}
	}
}

// Close 关闭审计日志记录器
func (a *AuditLogger) Close() error {
	close(a.stopChan)

	a.mu.Lock()
	defer a.mu.Unlock()

	// 刷新剩余缓冲区
	if err := a.flush(); err != nil {
		return err
	}

	// 关闭文件
	return a.logFile.Close()
}

// GetRecentLogs 获取最近的审计日志
func GetRecentLogs(logDir string, limit int) ([]AuditLogEntry, error) {
	// 读取今天的日志文件
	timestamp := time.Now().Format("2006-01-02")
	logPath := filepath.Join(logDir, fmt.Sprintf("audit_%s.log", timestamp))

	data, err := os.ReadFile(logPath)
	if err != nil {
		return nil, err
	}

	// 解析JSON（每行一个条目）
	var entries []AuditLogEntry
	lines := parseLines(string(data))

	// 从后往前读取（最新的在前）
	start := len(lines) - limit
	if start < 0 {
		start = 0
	}

	for i := len(lines) - 1; i >= start; i-- {
		var entry AuditLogEntry
		if err := json.Unmarshal([]byte(lines[i]), &entry); err == nil {
			entries = append(entries, entry)
		}
	}

	return entries, nil
}

// parseLines 解析文本为行
func parseLines(text string) []string {
	lines := make([]string, 0)
	current := ""

	for _, ch := range text {
		if ch == '\n' {
			if current != "" {
				lines = append(lines, current)
				current = ""
			}
		} else {
			current += string(ch)
		}
	}

	if current != "" {
		lines = append(lines, current)
	}

	return lines
}

// 全局审计日志记录器
var globalAuditLogger *AuditLogger
var auditLoggerOnce sync.Once

// GetAuditLogger 获取全局审计日志记录器
func GetAuditLogger() *AuditLogger {
	return globalAuditLogger
}

