package net.siegeln.cameleer.saas.audit;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Component
public class AuditRepositoryImpl implements AuditRepositoryCustom {

    private final JdbcTemplate jdbc;

    public AuditRepositoryImpl(JdbcTemplate jdbc) {
        this.jdbc = jdbc;
    }

    @Override
    public Page<AuditDto.AuditLogEntry> findFiltered(UUID tenantId, String action, String result,
                                                      Instant from, Instant to, String search,
                                                      Pageable pageable) {
        StringBuilder where = new StringBuilder("WHERE 1=1");
        List<Object> params = new ArrayList<>();

        if (tenantId != null) {
            where.append(" AND tenant_id = ?");
            params.add(tenantId);
        }
        if (action != null && !action.isBlank()) {
            where.append(" AND action = ?");
            params.add(action);
        }
        if (result != null && !result.isBlank()) {
            where.append(" AND result = ?");
            params.add(result);
        }
        if (from != null) {
            where.append(" AND created_at >= ?");
            params.add(Timestamp.from(from));
        }
        if (to != null) {
            where.append(" AND created_at <= ?");
            params.add(Timestamp.from(to));
        }
        if (search != null && !search.isBlank()) {
            where.append(" AND (actor_email ILIKE ? OR resource ILIKE ?)");
            String like = "%" + search + "%";
            params.add(like);
            params.add(like);
        }

        String countSql = "SELECT COUNT(*) FROM audit_log " + where;
        Long total = jdbc.queryForObject(countSql, Long.class, params.toArray());
        long totalCount = total != null ? total : 0;

        String dataSql = "SELECT * FROM audit_log " + where
                + " ORDER BY created_at DESC LIMIT ? OFFSET ?";
        List<Object> dataParams = new ArrayList<>(params);
        dataParams.add(pageable.getPageSize());
        dataParams.add(pageable.getOffset());

        List<AuditDto.AuditLogEntry> items = jdbc.query(dataSql, (rs, rowNum) -> mapRow(rs), dataParams.toArray());
        return new PageImpl<>(items, pageable, totalCount);
    }

    private AuditDto.AuditLogEntry mapRow(ResultSet rs) throws SQLException {
        Timestamp ts = rs.getTimestamp("created_at");
        return new AuditDto.AuditLogEntry(
                rs.getObject("id", UUID.class),
                rs.getString("actor_email"),
                rs.getObject("tenant_id", UUID.class),
                rs.getString("action"),
                rs.getString("resource"),
                rs.getString("environment"),
                rs.getString("result"),
                rs.getString("source_ip"),
                ts != null ? ts.toInstant() : null
        );
    }
}
