package com.zioinfo.kintex.work.schedule;

import com.zioinfo.kintex.auth.KintexPrincipal;
import com.zioinfo.kintex.common.error.ApiException;
import com.zioinfo.kintex.common.error.ErrorCode;
import com.zioinfo.kintex.system.SystemAccessGuard;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/** 일정 서비스. DataScope: 일반은 본인, 매니저/관리자는 전체. 편집은 소유자 본인. */
@Service
public class ScheduleService {

    private final ScheduleMapper mapper;
    private final SystemAccessGuard scope;

    public ScheduleService(ScheduleMapper mapper, SystemAccessGuard scope) {
        this.mapper = mapper;
        this.scope = scope;
    }

    public List<ScheduleDto> list(KintexPrincipal principal, String eventId, String fromAt, String toAt) {
        Map<String, Object> q = new HashMap<>();
        q.put("mineOnly", !scope.canSeeAll(principal));
        q.put("userId", principal.userId());
        q.put("eventId", eventId);
        q.put("fromAt", fromAt);
        q.put("toAt", toAt);
        return mapper.search(q).stream().map(ScheduleService::toDto).toList();
    }

    public ScheduleDto get(KintexPrincipal principal, String id) {
        Map<String, Object> r = mapper.findById(id);
        if (r == null) {
            throw new ApiException(ErrorCode.NOT_FOUND);
        }
        if (!scope.canSeeAll(principal) && !principal.userId().equals(str(r.get("ownerId")))) {
            throw new ApiException(ErrorCode.FORBIDDEN);
        }
        return toDto(r);
    }

    @Transactional
    public ScheduleDto create(KintexPrincipal principal, ScheduleSaveRequest req) {
        String id = "sc-" + UUID.randomUUID().toString().substring(0, 12);
        Map<String, Object> p = base(req);
        p.put("id", id);
        p.put("ownerId", principal.userId());
        p.put("ownerName", principal.displayName());
        mapper.insert(p);
        return get(principal, id);
    }

    @Transactional
    public ScheduleDto update(KintexPrincipal principal, String id, ScheduleSaveRequest req) {
        Map<String, Object> p = base(req);
        p.put("id", id);
        p.put("ownerId", principal.userId());
        if (mapper.update(p) == 0) {
            throw new ApiException(ErrorCode.FORBIDDEN, "본인 일정만 수정할 수 있습니다.");
        }
        return get(principal, id);
    }

    @Transactional
    public void delete(KintexPrincipal principal, String id) {
        if (mapper.delete(id, principal.userId()) == 0) {
            throw new ApiException(ErrorCode.FORBIDDEN, "본인 일정만 삭제할 수 있습니다.");
        }
    }

    private static Map<String, Object> base(ScheduleSaveRequest req) {
        Map<String, Object> p = new HashMap<>();
        p.put("eventId", req.eventId());
        p.put("title", req.title());
        p.put("scheduleType", req.scheduleType());
        p.put("importance", req.importance());
        p.put("startAt", req.startAt());
        p.put("endAt", req.endAt());
        p.put("allDay", req.allDay());
        p.put("location", req.location());
        p.put("content", req.content());
        p.put("color", req.color());
        return p;
    }

    private static ScheduleDto toDto(Map<String, Object> r) {
        return new ScheduleDto(str(r.get("id")), str(r.get("eventId")), str(r.get("ownerId")),
                str(r.get("ownerName")), str(r.get("title")), str(r.get("scheduleType")),
                str(r.get("importance")), str(r.get("startAt")), str(r.get("endAt")),
                bool(r.get("allDay")), str(r.get("location")), str(r.get("content")),
                str(r.get("color")), str(r.get("createdAt")));
    }
    private static String str(Object o) { return o == null ? null : String.valueOf(o); }
    private static boolean bool(Object o) {
        if (o instanceof Boolean b) return b;
        return o != null && Boolean.parseBoolean(String.valueOf(o));
    }
}
