// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module http

import chunked

// Response represents the result of the request
pub struct Response {
pub mut:
	text        string
	header      Header
	cookies     map[string]string
	status_code int
	version     Version
}

fn (mut resp Response) free() {
	unsafe { resp.header.data.free() }
}

// Formats resp to bytes suitable for HTTP response transmission
pub fn (resp Response) bytes() []byte {
	// TODO: build []byte directly; this uses two allocations
	// TODO: cookies
	return ('$resp.version $resp.status_code ${status_from_int(resp.status_code).str()}\r\n' +
		'${resp.header.render(version: resp.version)}\r\n' +
		'$resp.text').bytes()
}

// Parse a raw HTTP response into a Response object
pub fn parse_response(resp string) Response {
	mut header := new_header()
	// TODO: Cookie data type
	mut cookies := map[string]string{}
	first_header := resp.all_before('\n')
	mut status_code := 0
	if first_header.contains('HTTP/') {
		val := first_header.find_between(' ', ' ')
		status_code = val.int()
	}
	mut text := ''
	// Build resp header map and separate the body
	mut nl_pos := 3
	mut i := 1
	for {
		old_pos := nl_pos
		nl_pos = resp.index_after('\n', nl_pos + 1)
		if nl_pos == -1 {
			break
		}
		h := resp[old_pos + 1..nl_pos]
		// End of headers
		if h.len <= 1 {
			text = resp[nl_pos + 1..]
			break
		}
		i++
		pos := h.index(':') or { continue }
		mut key := h[..pos]
		val := h[pos + 2..].trim_space()
		header.add_custom(key, val) or { eprintln('$err; skipping header') }
	}
	// set cookies
	for cookie in header.values(.set_cookie) {
		parts := cookie.split_nth('=', 2)
		cookies[parts[0]] = parts[1]
	}
	if header.get(.transfer_encoding) or { '' } == 'chunked' || header.get(.content_length) or { '' } == '' {
		text = chunked.decode(text)
	}
	return Response{
		status_code: status_code
		header: header
		cookies: cookies
		text: text
	}
}