from http.server import BaseHTTPRequestHandler, HTTPServer
import json
from urllib.parse import parse_qs, urlsplit


messages = []


class Handler(BaseHTTPRequestHandler):
    protocol_version = "HTTP/1.1"

    def respond(self, status, data, headers=None):
        body = json.dumps(data, ensure_ascii=False).encode("utf-8")
        self.send_response(status)
        self.send_header("Content-Type", "application/json; charset=utf-8")
        self.send_header("Content-Length", str(len(body)))
        self.send_header("Connection", "close")
        self.send_header("Cache-Control", "no-store")
        for name, value in (headers or {}).items():
            self.send_header(name, value)
        self.end_headers()
        self.close_connection = True
        if self.command != "HEAD":
            self.wfile.write(body)

    def do_HEAD(self):
        self.do_GET()

    def do_GET(self):
        url = urlsplit(self.path)
        if url.path == "/api/hello":
            name = parse_qs(url.query).get("name", ["World"])[0]
            self.respond(200, {
                "message": f"こんにちは、{name}さん！",
                "received_x_lesson": self.headers.get("X-Lesson"),
            })
        elif url.path == "/api/messages":
            self.respond(200, {"messages": messages})
        elif url.path.startswith("/api/messages/"):
            identifier = url.path.removeprefix("/api/messages/")
            for message in messages:
                if str(message["id"]) == identifier:
                    self.respond(200, message)
                    return
            self.respond(404, {"error": "メッセージがありません"})
        elif url.path == "/redirect":
            self.respond(302, {"message": "転送先へ移動してください"},
                         {"Location": "/api/hello?name=Redirect"})
        else:
            self.respond(404, {"error": "そのパスはありません"})

    def do_POST(self):
        if urlsplit(self.path).path != "/api/messages":
            self.respond(404, {"error": "そのパスはありません"})
            return
        if self.headers.get("Transfer-Encoding"):
            self.respond(501, {"error": "この実習ではContent-Lengthを使います"})
            return
        if self.headers.get_content_type() != "application/json":
            self.respond(415, {"error": "application/jsonで送ってください"})
            return
        length_text = self.headers.get("Content-Length", "")
        if not length_text.isascii() or not length_text.isdecimal():
            self.respond(400, {"error": "Content-Lengthが必要です"})
            return
        length = int(length_text)
        if length > 16384:
            self.respond(413, {"error": "本文が大きすぎます"})
            return
        self.connection.settimeout(5)
        try:
            raw = self.rfile.read(length)
        except OSError:
            self.respond(408, {"error": "本文を受信できませんでした"})
            return
        if len(raw) != length:
            self.respond(400, {"error": "本文の長さが違います"})
            return
        try:
            data = json.loads(raw.decode("utf-8-sig"))
        except (UnicodeDecodeError, json.JSONDecodeError):
            self.respond(400, {"error": "UTF-8のJSONを送ってください"})
            return
        if not isinstance(data, dict) or not isinstance(data.get("text"), str):
            self.respond(400, {"error": "textは文字列にしてください"})
            return
        text = data["text"].strip()
        if not 1 <= len(text) <= 200:
            self.respond(400, {"error": "textは1〜200文字にしてください"})
            return
        self.save_message(text)

    def save_message(self, text):
        message = {"id": len(messages) + 1, "text": text}
        messages.append(message)
        self.respond(201, message, {"Location": f"/api/messages/{message['id']}"})


def main():
    with HTTPServer(("127.0.0.1", 8000), Handler) as server:
        print("http://127.0.0.1:8000/ を開いてください。終了は Ctrl+C", flush=True)
        try:
            server.serve_forever()
        except KeyboardInterrupt:
            print("サーバーを終了します")


if __name__ == "__main__":
    main()
