"""Convert iphone notes from JSON format into plain text files."""

import argparse
import datetime as dt
import json
import os
import re
from pathlib import Path
from typing import NamedTuple


def get_valid_filename(name):
    """Transform a string into a valid filename and return it."""
    s = str(name).strip().replace(" ", "_")
    s = re.sub(r"(?u)[^-\w.]", "", s)
    s = s.replace("_", " ")
    if s in {"", ".", ".."}:
        raise ValueError("Could not derive file name from '%s'" % name)
    return s


class Note(NamedTuple):
    """An extracted iphone note."""

    title: str
    text: str
    created: dt.datetime
    last_modified: dt.datetime

    @classmethod
    def from_obj(cls, obj) -> "Note":
        return cls(
            title=obj["title"],
            text=obj["plaintext"],
            created=cls._parse_time(obj["creation_time"]),
            last_modified=cls._parse_time(obj["modify_time"]),
        )

    @staticmethod
    def _parse_time(time_string: str) -> dt.datetime:
        return dt.datetime.strptime(time_string, "%Y-%m-%d %H:%M:%S %z")


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument(
        "filename", help="Name of the input JSON file, e.g. all_notes.json"
    )
    args = parser.parse_args()

    # fetch notes from file
    input_file = Path(args.filename)
    with input_file.open("r", encoding="utf-8") as file:
        data = json.load(file)

    # extract notes
    notes = [Note.from_obj(obj) for obj in data["notes"].values()]

    # write notes as plain text files
    output_folder = Path(__file__).parent / "output"
    output_folder.mkdir(exist_ok=True)
    for note in notes:
        filename = get_valid_filename(note.title)
        output_file = output_folder / f"{filename}.txt"
        with output_file.open("w", encoding="utf-8") as file:
            file.write(note.text)
        os.utime(
            output_file, (note.created.timestamp(), note.last_modified.timestamp())
        )

    print(f"Converted {len(notes)} notes into plain text files at: {output_folder}")


if __name__ == "__main__":
    main()