# frozen_string_literal: true

require "webrick"
require "uri"

module Dispatch
  module Adapter
    class Claude < Base
      module OAuth
        class CallbackServer
          SUCCESS_HTML = <<~HTML
            <!DOCTYPE html>
            <html>
            <head><title>Authentication Successful</title></head>
            <body>
              <h1>Authentication Successful</h1>
              <p>You can close this tab and return to your terminal.</p>
            </body>
            </html>
          HTML

          def initialize(port: 54_545, timeout: 300)
            @port = port
            @timeout = timeout
            @queue = Queue.new
            @server = nil
            @thread = nil
          end

          def callback_url
            "http://localhost:#{@port}/callback"
          end

          def start
            logger = WEBrick::Log.new(File::NULL, WEBrick::Log::FATAL)
            @server = WEBrick::HTTPServer.new(
              BindAddress: "127.0.0.1",
              Port: @port,
              Logger: logger,
              AccessLog: []
            )

            @server.mount_proc("/callback") do |req, res|
              if req.request_method == "GET"
                code  = req.query["code"]
                state = req.query["state"]

                if code
                  res.status = 200
                  res.content_type = "text/html; charset=utf-8"
                  res.body = SUCCESS_HTML
                  @queue << [code, state]
                  shutdown_async
                else
                  res.status = 400
                  res.body = "Missing code parameter"
                end
              else
                res.status = 405
                res.body = "Method Not Allowed"
              end
            end

            @server.mount_proc("/") do |_req, res|
              res.status = 404
              res.body = "Not Found"
            end

            @thread = Thread.new do
              @server.start
            rescue StandardError
              # Server was shut down
            end

            # Start a timeout watchdog
            Thread.new do
              sleep(@timeout)
              @queue << AuthenticationError.new(
                "OAuth callback timed out after #{@timeout}s — no browser response received.",
                provider: ClaudeErrors::PROVIDER
              )
              shutdown_async
            end
          end

          def await_code
            result = @queue.pop
            raise result if result.is_a?(Exception)

            result
          end

          def stop
            shutdown_async
            @thread&.join(5)
          rescue StandardError
            # Ignore errors during shutdown
          end

          private

          def shutdown_async
            return unless @server

            server = @server
            @server = nil
            Thread.new { server.shutdown rescue nil } # rubocop:disable Style/RescueModifier
          end
        end
      end
    end
  end
end
