import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

/**
 * Penyimpanan berkas teks: satu kontak per baris dengan format
 * id|nama|email|telepon. Setiap perubahan ditulis ulang seluruhnya
 * dengan charset UTF-8.
 */
public class KontakDaoBerkas implements KontakDao {

    private final Path berkas;

    public KontakDaoBerkas(Path berkas) {
        this.berkas = berkas;
    }

    @Override
    public List<Kontak> muatSemua() throws PersistensiGagalException {
        if (!Files.exists(berkas)) {
            return List.of();
        }
        List<Kontak> hasil = new ArrayList<>();
        try {
            List<String> barisSemua = Files.readAllLines(berkas, StandardCharsets.UTF_8);
            for (int i = 0; i < barisSemua.size(); i++) {
                String baris = barisSemua.get(i);
                if (baris.isBlank()) {
                    continue;
                }
                hasil.add(uraikan(baris, i + 1));
            }
            return hasil;
        } catch (IOException e) {
            throw new PersistensiGagalException(
                    "gagal membaca " + berkas, e);
        }
    }

    @Override
    public void tambah(Kontak kontak) throws PersistensiGagalException {
        List<Kontak> data = new ArrayList<>(muatSemua());
        data.add(kontak);
        tulisSemua(data);
    }

    @Override
    public void perbarui(Kontak kontak) throws PersistensiGagalException {
        List<Kontak> data = new ArrayList<>(muatSemua());
        for (int i = 0; i < data.size(); i++) {
            if (data.get(i).id() == kontak.id()) {
                data.set(i, kontak);
                tulisSemua(data);
                return;
            }
        }
        throw new PersistensiGagalException(
                "id " + kontak.id() + " tidak ada di " + berkas);
    }

    @Override
    public void hapus(int id) throws PersistensiGagalException {
        List<Kontak> data = new ArrayList<>(muatSemua());
        for (Kontak k : data) {
            if (k.id() == id) {
                data.remove(k);
                tulisSemua(data);
                return;
            }
        }
        throw new PersistensiGagalException(
                "id " + id + " tidak ada di " + berkas);
    }

    /** Mengubah satu baris berkas menjadi objek Kontak. */
    private static Kontak uraikan(String baris, int nomor)
            throws PersistensiGagalException {
        String[] bagian = baris.split("\\|", 4);
        if (bagian.length != 4) {
            throw new PersistensiGagalException(
                    "baris rusak pada nomor " + nomor + ": \"" + baris + "\"");
        }
        try {
            int id = Integer.parseInt(bagian[0].strip());
            return new Kontak(id, bagian[1], bagian[2], bagian[3]);
        } catch (NumberFormatException e) {
            throw new PersistensiGagalException(
                    "id bukan angka pada baris " + nomor + ": " + bagian[0]);
        }
    }

    /** Menulis ulang seluruh isi berkas dari daftar kontak. */
    private void tulisSemua(List<Kontak> data) throws PersistensiGagalException {
        StringBuilder teks = new StringBuilder();
        for (Kontak k : data) {
            teks.append(k.id()).append('|')
                    .append(k.nama()).append('|')
                    .append(k.email()).append('|')
                    .append(k.telepon()).append('\n');
        }
        try {
            Files.writeString(berkas, teks.toString(), StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new PersistensiGagalException(
                    "gagal menulis " + berkas, e);
        }
    }
}
