package service

import (
	"context"
	"kra/internal/biz/system"

	"kra/internal/service/dto"
)

type AuditService struct{ uc *system.AuditUsecase }

func NewAuditService(uc *system.AuditUsecase) *AuditService { return &AuditService{uc: uc} }

type AuditRecorder struct{ uc *system.AuditRecorderUsecase }

func NewAuditRecorder(uc *system.AuditRecorderUsecase) *AuditRecorder { return &AuditRecorder{uc: uc} }

func (s *AuditRecorder) RecordOperation(ctx context.Context, v *system.OperationRecord) error {
	return s.uc.RecordOperation(ctx, v)
}
func (s *AuditRecorder) RecordOperationRequest(ctx context.Context, value *dto.OperationRecordRequest) error {
	return s.RecordOperation(ctx, &system.OperationRecord{IP: value.IP, Method: value.Method, Path: value.Path, Status: value.Status, LatencyMS: value.LatencyMS, Agent: value.Agent, ErrorMessage: value.ErrorMessage, Body: value.Body, Response: value.Response, UserID: value.UserID, RequestID: value.RequestID, TraceID: value.TraceID, DeviceID: value.DeviceID})
}
func (s *AuditService) OperationsFilter(ctx context.Context, page, size int, path, method string, status int) ([]*dto.OperationRecordResponse, int64, error) {
	return s.Operations(ctx, page, size, &system.OperationRecord{Path: path, Method: method, Status: status})
}
func opDTO(v *system.OperationRecord) *dto.OperationRecordResponse {
	var user any = map[string]any{}
	if v.User != nil {
		user = convertUser(v.User)
	}
	return &dto.OperationRecordResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, IP: v.IP, Method: v.Method, Path: v.Path, Status: v.Status, LatencyMS: v.LatencyMS, Agent: v.Agent, ErrorMessage: v.ErrorMessage, Body: v.Body, Response: v.Response, UserID: v.UserID, RequestID: v.RequestID, TraceID: v.TraceID, DeviceID: v.DeviceID, User: user}
}
func (s *AuditService) Operations(ctx context.Context, page, size int, q *system.OperationRecord) ([]*dto.OperationRecordResponse, int64, error) {
	items, total, err := s.uc.ListOperations(ctx, page, size, q)
	if err != nil {
		return nil, 0, err
	}
	out := make([]*dto.OperationRecordResponse, 0, len(items))
	for _, v := range items {
		out = append(out, opDTO(v))
	}
	return out, total, nil
}
func (s *AuditService) Operation(ctx context.Context, id uint) (*dto.OperationRecordResponse, error) {
	v, err := s.uc.FindOperation(ctx, id)
	if err != nil {
		return nil, err
	}
	return opDTO(v), nil
}
func (s *AuditService) DeleteOperations(ctx context.Context, ids []int) error {
	return s.uc.DeleteOperations(ctx, ids)
}

func (s *AuditRecorder) RecordLogin(ctx context.Context, v *system.LoginLog) error {
	return s.uc.RecordLogin(ctx, v)
}
func (s *AuditRecorder) RecordLoginRequest(ctx context.Context, value *dto.LoginLogRequest) error {
	return s.RecordLogin(ctx, &system.LoginLog{Username: value.Username, IP: value.IP, Status: value.Status, ErrorMessage: value.ErrorMessage, Agent: value.Agent, UserID: value.UserID})
}
func (s *AuditService) LoginsFilter(ctx context.Context, page, size int, username string, status bool) ([]*dto.LoginLogResponse, int64, error) {
	return s.Logins(ctx, page, size, &system.LoginLog{Username: username, Status: status, FilterByStatus: status})
}
func loginDTO(v *system.LoginLog) *dto.LoginLogResponse {
	var user any = map[string]any{}
	if v.User != nil {
		user = convertUser(v.User)
	}
	return &dto.LoginLogResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, Username: v.Username, IP: v.IP, Status: v.Status, ErrorMessage: v.ErrorMessage, Agent: v.Agent, UserID: v.UserID, User: user}
}
func (s *AuditService) Logins(ctx context.Context, page, size int, q *system.LoginLog) ([]*dto.LoginLogResponse, int64, error) {
	items, total, err := s.uc.ListLogins(ctx, page, size, q)
	if err != nil {
		return nil, 0, err
	}
	out := make([]*dto.LoginLogResponse, 0, len(items))
	for _, v := range items {
		out = append(out, loginDTO(v))
	}
	return out, total, nil
}
func (s *AuditService) Login(ctx context.Context, id uint) (*dto.LoginLogResponse, error) {
	v, err := s.uc.FindLogin(ctx, id)
	if err != nil {
		return nil, err
	}
	return loginDTO(v), nil
}
func (s *AuditService) DeleteLogins(ctx context.Context, ids []int) error {
	return s.uc.DeleteLogins(ctx, ids)
}

func (s *AuditRecorder) RecordDataAccess(ctx context.Context, v *system.DataAccessLog) error {
	return s.uc.RecordDataAccess(ctx, v)
}
func (s *AuditRecorder) RecordDataAccessRequest(ctx context.Context, value *dto.DataAccessRecordRequest) error {
	return s.RecordDataAccess(ctx, &system.DataAccessLog{EventType: value.EventType, Operation: value.Operation, UserID: value.UserID, AuthorityID: value.AuthorityID, RequestID: value.RequestID, Method: value.Method, Path: value.Path, Detail: value.Detail})
}
func (s *AuditService) DataAccessRequest(ctx context.Context, req *dto.DataAccessListRequest) ([]*dto.DataAccessLogResponse, int64, error) {
	return s.DataAccess(ctx, req.Page, req.PageSize, &system.DataAccessLog{EventType: req.EventType, TargetTable: req.TargetTable})
}
func dataAccessDTO(v *system.DataAccessLog) *dto.DataAccessLogResponse {
	return &dto.DataAccessLogResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, EventType: v.EventType, TargetTable: v.TargetTable, Operation: v.Operation, UserID: v.UserID, AuthorityID: v.AuthorityID, Scope: v.Scope, RequestID: v.RequestID, Method: v.Method, Path: v.Path, Detail: v.Detail}
}
func (s *AuditService) DataAccess(ctx context.Context, page, size int, q *system.DataAccessLog) ([]*dto.DataAccessLogResponse, int64, error) {
	items, total, err := s.uc.ListDataAccess(ctx, page, size, q)
	if err != nil {
		return nil, 0, err
	}
	out := make([]*dto.DataAccessLogResponse, 0, len(items))
	for _, v := range items {
		out = append(out, dataAccessDTO(v))
	}
	return out, total, nil
}
func (s *AuditService) DeleteDataAccess(ctx context.Context, ids []uint) error {
	return s.uc.DeleteDataAccess(ctx, ids)
}
