import java.time.LocalDate;
import java.util.List;

/**
 * Lapisan layanan: pemilik aturan bisnis aplikasi web manajemen tugas.
 * Seluruh operasi lewat sini; lapisan web tidak pernah menyentuh repository
 * secara langsung, dan repository tidak pernah tahu bahwa HTTP ada.
 * Hari operasional disuntik lewat konstruktor agar aturan "tenggat lampau"
 * bisa diuji dengan tanggal beku, bukan LocalDate.now().
 */
public class LayananTugasWeb {

    /** Batas tugas berstatus TODO per pemilik: aturan bisnis lapisan layanan. */
    public static final int BATAS_TUGAS_AKTIF = 5;

    private final RepositoryTugasWeb repository;
    private final LocalDate hariIni;

    public LayananTugasWeb(RepositoryTugasWeb repository, LocalDate hariIni) {
        this.repository = repository;
        this.hariIni = hariIni;
    }

    /** Hari operasional aplikasi, disuntik lewat konstruktor. */
    public LocalDate hariIni() {
        return hariIni;
    }

    /**
     * Menyusun tugas baru: status selalu TODO (klien tidak boleh menetapkannya),
     * tenggat wajib belum lampau, dan pemilik belum menyentuh batas tugas aktif.
     * Validasi bentuk field menyusul di Bagian 2.
     */
    public TugasWeb buat(PermintaanTugas permintaan) {
        long aktif = repository.semua().stream()
                .filter(t -> t.pemilik().equals(permintaan.pemilik()))
                .filter(t -> t.status() == StatusTugasWeb.TODO)
                .count();
        if (aktif >= BATAS_TUGAS_AKTIF) {
            throw new AturanBisnisException("pemilik " + permintaan.pemilik()
                    + " sudah memiliki " + BATAS_TUGAS_AKTIF + " tugas TODO");
        }
        TugasWeb baru = new TugasWeb(0, permintaan.judul(), permintaan.pemilik(),
                StatusTugasWeb.TODO, LocalDate.parse(permintaan.tenggat()));
        return repository.simpanBaru(baru);
    }

    /** Seluruh tugas terurut id. */
    public List<TugasWeb> daftar() {
        return repository.semua();
    }

    /** Satu tugas berdasarkan id; 404 bila tidak ada. */
    public TugasWeb cari(int id) {
        return repository.cari(id)
                .orElseThrow(() -> new TugasTidakDitemukanException(id));
    }

    /**
     * Memperbarui judul, pemilik, dan tenggat; status dipertahankan apa adanya
     * karena transisi status hanya boleh lewat tandaiSelesai.
     */
    public TugasWeb ubah(int id, PermintaanTugas permintaan) {
        TugasWeb tugas = cari(id);
        TugasWeb baru = new TugasWeb(id, permintaan.judul(), permintaan.pemilik(),
                tugas.status(), LocalDate.parse(permintaan.tenggat()));
        return repository.perbarui(baru)
                .orElseThrow(() -> new TugasTidakDitemukanException(id));
    }

    /** Menandai tugas selesai; 409 bila tugas memang sudah SELESAI. */
    public TugasWeb tandaiSelesai(int id) {
        TugasWeb tugas = cari(id);
        if (tugas.status() == StatusTugasWeb.SELESAI) {
            throw new AturanBisnisException("tugas #" + id
                    + " sudah SELESAI, tidak bisa ditandai selesai ulang");
        }
        TugasWeb selesai = tugas.denganStatus(StatusTugasWeb.SELESAI);
        return repository.perbarui(selesai)
                .orElseThrow(() -> new TugasTidakDitemukanException(id));
    }

    /** Menghapus tugas; 404 bila id tidak ada. */
    public void hapus(int id) {
        cari(id);
        repository.hapus(id);
    }
}
