package webcontroller

import (
	"fmt"
	"html/template"
	"net/http"
	"strconv"

	"github.com/julienschmidt/httprouter"
)

func (wc *WebController) themeHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	w.Header().Set("Content-Type", "text/css")
	w.Write([]byte(userStyleFromRequest(r)))
}

func userStyleFromRequest(r *http.Request) (s template.CSS) {
	// Get the chosen style from the URL
	var style = r.URL.Query().Get("style")
	var hue = -1

	if hueStr := r.URL.Query().Get("hue"); hueStr != "" {
		hue, _ = strconv.Atoi(hueStr)
	}

	// If the URL style was empty use the cookie value
	if style == "" {
		if cookie, err := r.Cookie("style"); err == nil {
			style = cookie.Value
		}
	}
	if hue == -1 {
		if cookie, err := r.Cookie("hue"); err == nil {
			hue, _ = strconv.Atoi(cookie.Value)
		}
	}

	return userStyle(style, hue)
}

func userStyle(style string, hue int) template.CSS {
	var (
		def      styleSheet
		light    styleSheet
		hasLight bool
	)

	switch style {
	default:
		fallthrough
	case "nova":
		def = novaStyle
	case "adwaita":
		def = adwaitaDarkStyle
		light = adwaitaLightStyle
		hasLight = true
	case "nord":
		def = nordDarkStyle
		light = nordLightStyle
		hasLight = true
	case "nord_dark":
		def = nordDarkStyle
	case "nord_light", "snowstorm":
		def = nordLightStyle
	case "solarized":
		def = solarizedDarkStyle
		light = solarizedLightStyle
		hasLight = true
	case "solarized_dark":
		def = solarizedDarkStyle
	case "solarized_light":
		def = solarizedLightStyle
	case "classic":
		def = classicStyle
		hue = -1 // Does not support custom hues
	case "purple_drain":
		def = purpleDrainStyle
		hue = -1 // Does not support custom hues
	case "maroon":
		def = maroonStyle
	case "hacker":
		def = hackerStyle
		hue = -1 // Does not support custom hues
	case "canta":
		def = cantaNovaStyle
	case "skeuos":
		def = skeuosNovaStyle
	case "sweet":
		def = sweetNovaStyle
	case "adwaita_dark":
		def = adwaitaDarkStyle
	case "adwaita_light":
		def = adwaitaLightStyle
	case "nova98":
		def = nova98Style
	case "nova98_dark":
		def = nova98StyleDark
	}

	if hue >= 0 && hue <= 360 {
		def = def.withHue(hue)
		light = light.withHue(hue)
	}

	if hasLight {
		return template.CSS(def.withLight(light))
	} else {
		return template.CSS(def.String())
	}
}

type styleSheet struct {
	Link                HSL // Based on Highlight if undefined
	Input               CSS
	InputHover          CSS
	InputText           CSS
	InputDisabledText   CSS
	HighlightBackground CSS
	Highlight           HSL // Links, highlighted buttons, list navigation
	HighlightText       HSL // Text on buttons
	Danger              HSL
	ScrollbarForeground CSS // Based on Input if undefined
	ScrollbarHover      CSS // Based on ScrollbarForeground if undefined

	BackgroundColor   HSL
	Background        CSS
	BackgroundText    HSL
	BackgroundPattern CSS
	Navigation        CSS
	BodyColor         HSL
	BodyBackground    CSS
	BodyText          HSL
	Separator         HSL
	CardColor         HSL
	CardText          HSL

	// Colors to use in graphs
	Chart1 HSL
	Chart2 HSL
	Chart3 HSL

	StyleOverrides string
}

func (s styleSheet) withDefaults() styleSheet {
	// Set default colors
	var noColor = HSL{0, 0, 0}
	var defaultHSL = func(target *HSL, def HSL) {
		if *target == noColor {
			*target = def
		}
	}
	var defaultCSS = func(target *CSS, def CSS) {
		if *target == nil {
			*target = def
		}
	}
	defaultHSL(&s.Link, s.Highlight.Add(0, 0, -.05))
	defaultCSS(&s.ScrollbarForeground, s.Input)
	defaultCSS(&s.ScrollbarHover, s.InputHover)
	defaultHSL(&s.Chart1, s.Highlight)
	defaultHSL(&s.Chart2, s.Chart1.Add(120, 0, 0))
	defaultHSL(&s.Chart3, s.Chart2.Add(120, 0, 0))
	defaultCSS(&s.HighlightBackground, s.Highlight)
	defaultCSS(&s.Background, s.BackgroundColor)
	defaultCSS(&s.BackgroundPattern, s.BackgroundColor)
	defaultCSS(&s.Navigation, RawCSS("none"))
	defaultCSS(&s.BodyBackground, s.BodyColor)
	defaultHSL(&s.BackgroundText, s.BodyText)
	defaultHSL(&s.Separator, s.BodyColor.Add(0, 0, .06))

	return s
}

func (s styleSheet) withHue(hue int) styleSheet {
	s = s.withDefaults()

	var setHue = func(c CSS) CSS {
		if hsl, ok := c.(HSL); ok {
			hsl.Hue = hue
			return hsl
		} else {
			return c
		}
	}

	s.Input = setHue(s.Input)
	s.InputHover = setHue(s.InputHover)
	s.InputText = setHue(s.InputText)
	s.InputDisabledText = setHue(s.InputDisabledText)
	s.ScrollbarForeground = setHue(s.ScrollbarForeground)
	s.ScrollbarHover = setHue(s.ScrollbarHover)
	s.BackgroundColor.Hue = hue
	s.Background = setHue(s.Background)
	s.BackgroundText.Hue = hue
	s.BackgroundPattern = setHue(s.BackgroundPattern)
	s.Navigation = setHue(s.Navigation)
	s.BodyColor.Hue = hue
	s.BodyBackground = setHue(s.BodyBackground)
	s.BodyText.Hue = hue
	s.Separator.Hue = hue
	s.CardColor.Hue = hue
	s.CardText.Hue = hue
	return s
}

func (s styleSheet) String() string {
	s = s.withDefaults()

	return fmt.Sprintf(
		`:root {
	--link_color:                 %s;
	--input_background:           %s;
	--input_hover_background:     %s;
	--input_text:                 %s;
	--input_disabled_text:        %s;
	--highlight_background:       %s;
	--highlight_color:            %s;
	--highlight_text_color:       %s;
	--danger_color:               %s;
	--danger_text_color:          %s;
	--scrollbar_foreground_color: %s;
	--scrollbar_hover_color:      %s;

	--background_color:         %s;
	--background:               %s;
	--background_text_color:    %s;
	--background_pattern_color: %s;
	--navigation_background:    %s;
	--body_color:               %s;
	--body_background:          %s;
	--body_text_color:          %s;
	--separator:                %s;
	--shaded_background:        %s;
	--card_color:               %s;

	--chart_1_color: %s;
	--chart_2_color: %s;
	--chart_3_color: %s;

	--shadow_color: %s;
}

%s
`,
		s.Link.CSS(),
		s.Input.CSS(),
		s.InputHover.CSS(),
		s.InputText.CSS(),
		s.InputDisabledText.CSS(),
		s.HighlightBackground.CSS(),
		s.Highlight.CSS(),
		s.HighlightText.CSS(),
		s.Danger.CSS(),
		s.HighlightText.CSS(),
		s.ScrollbarForeground.CSS(),
		s.ScrollbarHover.CSS(),
		s.BackgroundColor.CSS(),
		s.Background.CSS(),
		s.BackgroundText.CSS(),
		s.BackgroundPattern.CSS(),
		s.Navigation.CSS(),
		s.BodyColor.CSS(),
		s.BodyBackground.CSS(),
		s.BodyText.CSS(),
		s.Separator.CSS(),
		s.BodyColor.WithAlpha(0.9).CSS(), // shaded_background
		s.CardColor.CSS(),
		s.Chart1.CSS(),
		s.Chart2.CSS(),
		s.Chart3.CSS(),
		s.BodyColor.Darken(0.8).CSS(),
		s.StyleOverrides,
	)
}

func (dark styleSheet) withLight(light styleSheet) string {
	return fmt.Sprintf(
		`%s

@media (prefers-color-scheme: light) {
	%s
}`,
		dark.String(),
		light.String(),
	)
}

// Following are all the available styles

var purpleDrainStyle = styleSheet{
	Input:               RGBA{77, 19, 236, .3},
	InputHover:          RGBA{77, 19, 236, .4},
	InputText:           HSL{0, 0, .9},
	InputDisabledText:   HSL{266, .85, .4},
	HighlightBackground: NewGradient(160, HSL{150, .84, .39}, HSL{85, .85, .35}),
	Highlight:           HSL{117, .63, .46},
	HighlightText:       HSL{0, 0, 0},
	Danger:              HSL{357, .63, .46},
	ScrollbarForeground: HSL{266, .85, .40},
	ScrollbarHover:      HSL{266, .85, .50},

	BackgroundColor:   HSL{270, .84, .12},
	Background:        NewGradient(120, HSL{255, .84, .16}, HSL{300, .85, .14}),
	BackgroundPattern: RawCSS("none"),
	Navigation:        RawCSS("none"),
	BodyColor:         HSL{274, .9, .14},
	BodyBackground:    NewGradient(120, HSL{255, .84, .18}, HSL{300, .85, .16}),
	BodyText:          HSL{0, 0, .8},
	CardColor:         HSL{275, .8, .18},
}

var classicStyle = styleSheet{
	Input:             HSL{0, 0, .18},
	InputHover:        HSL{0, 0, .22},
	InputText:         HSL{0, 0, .9},
	InputDisabledText: HSL{0, 0, .4},
	Highlight:         HSL{89, .60, .45},
	HighlightText:     HSL{0, 0, 0},
	Danger:            HSL{339, .65, .31},

	BackgroundColor: HSL{0, 0, .08},
	BodyColor:       HSL{0, 0, .12},
	BodyText:        HSL{0, 0, .8},
	CardColor:       HSL{0, 0, .16},
}

var novaStyle = styleSheet{
	Input:             HSL{94, 1, .1},
	InputHover:        HSL{94, 1, .15},
	InputText:         HSL{0, 0, .9},
	InputDisabledText: HSL{0, 0, .4},
	Highlight:         HSL{94, .70, .45},
	HighlightText:     HSL{0, 0, 0},
	Danger:            HSL{339, .65, .31},

	BackgroundColor: HSL{94, 1, .02},
	BodyColor:       HSL{94, 1, .04},
	BodyText:        HSL{94, 1, .9},
	CardColor:       HSL{94, 1, .06},
}

var maroonStyle = styleSheet{
	Input:             HSL{0, .8, .20}, // hsl(0, 87%, 40%)
	InputHover:        HSL{0, .8, .25},
	InputText:         HSL{0, 0, 1},
	InputDisabledText: HSL{0, 0, .5},
	Highlight:         HSL{137, 1, .37}, //hsl(137, 100%, 37%)
	HighlightText:     HSL{0, 0, 0},
	Danger:            HSL{9, .96, .42}, //hsl(9, 96%, 42%)

	BackgroundColor: HSL{0, .7, .05},
	BodyColor:       HSL{0, .8, .08}, // HSL{0, .8, .15},
	BodyText:        HSL{0, 0, .8},
	CardColor:       HSL{0, .9, .14},
}

var hackerStyle = styleSheet{
	Input:             HSL{0, 0, .1},
	InputHover:        HSL{0, 0, .15},
	InputText:         HSL{0, 0, 1},
	InputDisabledText: HSL{0, 0, .5},
	Highlight:         HSL{120, .8, .5},
	HighlightText:     HSL{0, 0, 0},
	Danger:            HSL{0, 1, .4},

	BackgroundColor: HSL{0, 0, 0},
	BodyColor:       HSL{0, 0, .03},
	BodyText:        HSL{0, 0, .8},
	CardColor:       HSL{120, .4, .05},
}

var cantaNovaStyle = styleSheet{
	Input:             HSL{167, .06, .30}, // hsl(167, 6%, 30%)
	InputHover:        HSL{167, .06, .35}, // hsl(167, 6%, 30%)
	InputText:         HSL{0, 0, 1},
	InputDisabledText: HSL{0, 0, .5},
	Highlight:         HSL{165, 1, .40}, // hsl(165, 100%, 40%)
	HighlightText:     HSL{0, 0, 0},
	Danger:            HSL{40, 1, .5}, // hsl(40, 100%, 50%)

	BackgroundColor: HSL{180, .04, .16},
	BodyColor:       HSL{168, .05, .21},
	BodyText:        HSL{0, 0, .8},
	CardColor:       HSL{170, .05, .26},
}

var skeuosNovaStyle = styleSheet{
	Input:             HSL{226, .15, .23}, //hsl(226, 15%, 23%)
	InputHover:        HSL{226, .15, .28},
	InputText:         HSL{60, .06, .93},
	InputDisabledText: HSL{0, 0, .5},
	Highlight:         HSL{282, .65, .54}, // hsl(282, 65%, 54%)
	HighlightText:     HSL{0, 0, 1},
	Danger:            HSL{0, .79, .43}, // hsl(0, 79%, 43%)

	BackgroundColor: HSL{232, .14, .11}, //hsl(232, 14%, 11%)
	BodyColor:       HSL{229, .14, .16}, // hsl(229, 14%, 16%)
	BodyText:        HSL{60, .06, .93},  // hsl(60, 6%, 93%)
	CardColor:       HSL{225, .14, .17}, // hsl(225, 14%, 17%)
}

var (
	nord0  = HSL{220, .16, .22} // Dark
	nord1  = HSL{222, .16, .28} // Dark
	nord2  = HSL{220, .17, .32} // Dark
	nord3  = HSL{220, .16, .36} // Light
	nord4  = HSL{219, .28, .88} // Light
	nord5  = HSL{218, .27, .92} // Light
	nord6  = HSL{218, .27, .94} // Light
	nord7  = HSL{179, .25, .65} // Teal
	nord8  = HSL{193, .43, .67} // Light blue
	nord11 = HSL{354, .42, .56} // Red
	nord14 = HSL{92, .28, .65}  // Green
)

var nordDarkStyle = styleSheet{
	Input:               nord3.Add(0, 0, 0.01),
	InputHover:          nord3.Add(0, 0, 0.03),
	InputText:           nord5,
	InputDisabledText:   nord0,
	Highlight:           nord14,
	HighlightText:       nord0,
	Danger:              nord11,
	ScrollbarForeground: nord7,
	ScrollbarHover:      nord8,

	BackgroundColor: nord0,
	BodyColor:       nord1,
	BodyText:        nord4,
	CardColor:       nord2,
}

var nordLightStyle = styleSheet{
	Link:                HSL{92, .40, .32},
	Input:               nord4.Add(0, 0, -0.04),
	InputHover:          nord4.Add(0, 0, -0.06),
	InputText:           nord0,
	InputDisabledText:   nord6,
	Highlight:           nord14,
	HighlightText:       nord1,
	Danger:              nord11,
	ScrollbarForeground: nord7,
	ScrollbarHover:      nord8,

	BackgroundColor:   nord4,
	BackgroundText:    nord0,
	BodyColor:         nord6,
	BodyText:          nord2,
	Separator:         nord4,
	BackgroundPattern: nord4,
	CardColor:         nord5,
}

var sweetNovaStyle = styleSheet{
	Input:             HSL{229, .25, .18}, // hsl(229, 25%, 14%)
	InputHover:        HSL{229, .25, .23}, // hsl(229, 25%, 14%)
	InputText:         HSL{223, .13, .79},
	InputDisabledText: HSL{0, 0, .5},
	Highlight:         HSL{296, .88, .44},
	HighlightText:     HSL{0, 0, 0},
	Danger:            HSL{356, 1, .64}, // hsl(356, 100%, 64%)

	BackgroundColor: HSL{225, .25, .06}, // hsl(225, 25%, 6%)
	BodyColor:       HSL{228, .25, .12}, // hsl(228, 25%, 12%)
	BodyText:        HSL{223, .13, .79}, // hsl(223, 13%, 79%)
	CardColor:       HSL{229, .25, .14}, // hsl(229, 25%, 14%)
}

var adwaitaDarkStyle = styleSheet{
	Input:             RGBA{255, 255, 255, .06},
	InputHover:        RGBA{255, 255, 255, .11},
	InputText:         HSL{0, 0, 1},
	InputDisabledText: HSL{0, 0, .5},
	Highlight:         HSL{152, .62, .39}, // hsl(152, 62%, 39%)
	HighlightText:     HSL{0, 0, 0},
	Danger:            HSL{9, 1, .69}, // hsl(9, 100%, 69%)

	BackgroundColor: HSL{0, 0, .12},
	BodyColor:       HSL{0, 0, .14},
	BodyText:        HSL{0, 0, 1},
	CardColor:       HSL{0, 0, .21},
}

var adwaitaLightStyle = styleSheet{
	Input:             RGBA{0, 0, 0, .06},
	InputHover:        RGBA{0, 0, 0, .11},
	InputText:         HSL{0, 0, .2},
	InputDisabledText: HSL{0, 0, .7},
	Highlight:         HSL{152, .62, .47}, // hsl(152, 62%, 47%)
	HighlightText:     HSL{0, 0, 1},
	Danger:            HSL{356, .75, .43}, // hsl(356, 75%, 43%)

	BackgroundColor: HSL{0, 0, .92},
	BodyColor:       HSL{0, 0, .98},
	BodyText:        HSL{0, 0, .2},
	Separator:       HSL{0, 0, .86},
	CardColor:       HSL{0, 0, 1},
}

var solarizedDarkStyle = styleSheet{
	Input:             HSL{192, .81, .18}, // hsl(194, 14%, 40%)
	InputHover:        HSL{192, .81, .23}, // hsl(196, 13%, 45%)
	InputText:         HSL{180, .07, .80}, // hsl(44, 87%, 94%)
	InputDisabledText: HSL{194, .14, .30}, // hsl(194, 14%, 40%)
	Highlight:         HSL{68, 1, .30},    // hsl(68, 100%, 30%)
	HighlightText:     HSL{192, .81, .14}, // hsl(192, 100%, 11%)
	Danger:            HSL{1, .71, .52},   // hsl(1, 71%, 52%)

	BackgroundColor: HSL{192, 1, .11},   //hsl(192, 100%, 11%)
	BodyColor:       HSL{192, .81, .14}, // hsl(192, 81%, 14%)
	BodyText:        HSL{180, .07, .60}, // hsl(180, 7%, 60%)
	CardColor:       HSL{192, .81, .16},
}

var solarizedLightStyle = styleSheet{
	Input:             HSL{46, .42, .84},
	InputHover:        HSL{46, .42, .80},
	InputText:         HSL{194, .14, .20}, // hsl(192, 81%, 14%)
	InputDisabledText: HSL{44, .87, .94},
	Highlight:         HSL{68, 1, .30}, // hsl(68, 100%, 30%)
	HighlightText:     HSL{44, .87, .94},
	Danger:            HSL{1, .71, .52}, // hsl(1, 71%, 52%)

	BackgroundColor: HSL{46, .42, .88}, // hsl(46, 42%, 88%)
	BackgroundText:  HSL{192, .81, .14},
	BodyColor:       HSL{44, .87, .94},  // hsl(44, 87%, 94%)
	BodyText:        HSL{194, .14, .40}, // hsl(194, 14%, 40%)
	Separator:       HSL{46, .42, .88},
	CardColor:       HSL{44, .87, .92},
}

const override98 = `
button, .button,
dialog,
.highlight_border,
.page_content,
footer, .footer_content,
.card,
.window,
.block,
.sharebar,
.directory_sorters, .directory_area,
.container > .directory,
.file_preview > .directory,
.directory > .node,
.file, .file_button,
.upload_task,
.add_button,
.expandable,
.upload_widget {
	border: none !important;
	border-radius: 0 !important;
	box-shadow: inset -1px -1px #0a0a0a,
		inset 1px 1px #dfdfdf,
		inset -2px -2px grey,
		inset 2px 2px #fff !important;
}
.window, .page_content, .file_button, .expandable, pre {
	padding: 3px !important;
}
.window > .header,
.headerbar,
.upload_widget > .header {
	background: linear-gradient(90deg,navy,#1084d0) !important;
	color: #fff !important;
}
.tab_bar > button, .tab_bar > .button {
	border-top-left-radius: 3px !important;
	border-top-right-radius: 3px !important;
	box-shadow: inset -1px 0 #0a0a0a,inset 1px 1px #dfdfdf,inset -2px 0 grey,inset 2px 2px #fff !important;
}
.directory > tr {
	border: none !important;
}
.button_toggle_navigation {
	padding: 8px !important;
}

input[type="email"],
input[type="number"],
input[type="password"],
input[type="text"],
input[type="date"],
select, textarea, pre {
	border-radius: 0 !important;
	border: none !important;
	background-color: #fff !important;
	box-shadow: inset -1px -1px #fff,
		inset 1px 1px grey,
		inset -2px -2px #dfdfdf,
		inset 2px 2px #0a0a0a !important;
}
code {
	border-radius: 0 !important;
	background-color: #fff !important;
}

.file_preview,
hr,
.toolbar > .separator,
.toolbar > .grid > .separator,
.highlight_shaded {
	border-radius: 0 !important;
	border: none !important;
	box-shadow: inset -1px -1px #fff,
		inset 1px 1px grey,
		inset -2px -2px #dfdfdf,
		inset 2px 2px #0a0a0a !important;
}
`

var nova98Style = styleSheet{
	Input:             RGB{190, 190, 190},
	InputHover:        RGB{220, 220, 220},
	InputText:         RGB{0, 0, 0},
	InputDisabledText: RGB{128, 128, 128},
	Highlight:         HSL{240, 1, .5}, // hsl(68, 100%, 30%)
	HighlightText:     HSL{0, 1, 1},
	Danger:            HSL{1, .71, .52}, // hsl(1, 71%, 52%)

	BackgroundColor: HSL{180, 1, .25},
	BackgroundText:  HSL{0, 1, 1},
	BodyColor:       HSL{0, 0, .75},
	BodyText:        HSL{0, 0, 0},
	Separator:       HSL{0, 1, 1},
	CardColor:       HSL{0, 0, .75},

	StyleOverrides: override98,
}

var nova98StyleDark = styleSheet{
	Input:             HSL{0, 0, .25},
	InputHover:        HSL{0, 0, .30},
	InputText:         RGB{255, 255, 255},
	InputDisabledText: RGB{128, 128, 128},
	Highlight:         HSL{240, 1, .7},
	HighlightText:     HSL{0, 1, 1},
	Danger:            HSL{1, .71, .7},
	Link:              HSL{240, 1, .8},

	BackgroundColor: HSL{180, 1, .08},
	BackgroundText:  HSL{0, 1, 1},
	BodyColor:       HSL{0, 0, .25},
	BodyText:        HSL{0, 1, 1},
	Separator:       HSL{0, 0, .33},
	CardColor:       HSL{0, 0, .25},

	StyleOverrides: `
:root {
	--border_98: inset -1px -1px #222,
		inset 1px 1px #666,
		inset -2px -2px #333,
		inset 2px 2px #555;
	--inset_98: inset -1px -1px #666,
		inset 1px 1px #111,
		inset -2px -2px #555,
		inset 2px 2px #333;
}

button, .button,
dialog,
fieldset,
.highlight_border,
.page_content,
footer, .footer_content,
.card,
.window,
.block,
.sharebar,
.directory_sorters, .directory_area,
.container > .directory,
.file_preview > .directory,
.directory > .node,
.file, .file_button,
.upload_task,
.add_button,
.expandable,
.upload_widget,
.highlight_shaded {
	border: none !important;
	border-radius: 0 !important;
	box-shadow: var(--border_98) !important;
}
legend {
	background-color: var(--body_color);
	border: none !important;
}
.window, .page_content, .file_button, .expandable, pre {
	padding: 3px !important;
}
.window > .header,
.headerbar,
.upload_widget > .header {
	background: linear-gradient(90deg, #003d66, #005c99) !important;
	color: #fff !important;
}
.tab_bar > button, .tab_bar > .button {
	border-top-left-radius: 3px !important;
	border-top-right-radius: 3px !important;
	box-shadow: var(--border_98) !important;
}
.directory > tr {
	border: none !important;
}
.button_toggle_navigation {
	padding: 8px !important;
}

input[type="email"],
input[type="number"],
input[type="password"],
input[type="text"],
input[type="date"],
select, textarea, pre {
	border-radius: 0 !important;
	border: none !important;
	box-shadow: var(--inset_98) !important;
}
code {
	border-radius: 0 !important;
}

.file_preview,
hr,
.toolbar > .separator,
.toolbar > .grid > .separator {
	border-radius: 0 !important;
	border: none !important;
	box-shadow: var(--inset_98) !important;
}
`,
}
