#pragma once

#include "esphome/core/component.h"
#include "esphome/components/uart/uart.h"
#include "esphome/components/api/custom_api_device.h"
#ifdef USE_LIGHT
#include "esphome/components/light/light_output.h"
#endif
#ifdef USE_FAN
#include "esphome/components/fan/fan.h"
#endif

namespace esphome {
namespace hauslane {

static const unsigned char MSG_START[] = {0x08, 0x08, 0x08, 0xfe, 0xc0};
static const unsigned char MSG_END[] = {0xc0, 0xce, 0xce, 0xce};
static const uint8_t START_LEN=5;
static const uint8_t END_LEN=4;
static const int DELAY=250; // how long to press/release buttons in ms

class Hauslane : public Component, public uart::UARTDevice, public api::CustomAPIDevice {
	public:
		void setup() override;
		void loop() override;
		void dump_config() override;
		void set_pin_timer(GPIOPin *pin) {this->pin_timer=pin;}
		void set_pin_up(GPIOPin *pin) {this->pin_up=pin;}
		void set_pin_down(GPIOPin *pin) {this->pin_down=pin;}
		void set_pin_light(GPIOPin *pin) {this->pin_light=pin;}
		void set_pin_power(GPIOPin *pin) {this->pin_power=pin;}
		void set_light(bool binary);
		void set_speed(int new_speed);
		void register_light_func(const std::function<void(bool)> &func) { this->send_light_state = func; }
		void register_fan_func(const std::function<void(int)> &func) { this->send_fan_speed = func; }

	protected:
		bool reading = false;
		size_t pos = 0;
		std::vector<uint8_t> rx_message;
		void parse_state();
		void set_state(bool set_light, uint8_t set_speed);
		bool light_cur=false;
		bool light_target=false;
		uint8_t speed=0;
		uint8_t speed_target=0;
		bool meet_target=false;
		bool power=false;
		unsigned long last_press=0;
		GPIOPin *pin_timer;
		GPIOPin *pin_up;
		GPIOPin *pin_down;
		GPIOPin *pin_light;
		GPIOPin *pin_power;
		GPIOPin *last_button;
		void command(std::string command);
		void button_press(GPIOPin *pin, bool val);
		std::function<void(bool)> send_light_state;
		std::function<void(int)> send_fan_speed;
};

class HauslaneChild {
	public:
		void set_parent(Hauslane *parent) {this->parent = parent;}

	protected:
		Hauslane *parent;
};

#ifdef USE_LIGHT
class HauslaneLight : public light::LightOutput, public Component, public HauslaneChild {
	public:
		void setup() override;
		void dump_config() override;
		light::LightTraits get_traits() override;
		void setup_state(light::LightState *state) override {this->light_state_ = state;}
		void set_state(bool binary);

	protected:
		void write_state(light::LightState *state) override;
		light::LightState *light_state_{nullptr};
};
#endif

#ifdef USE_FAN
class HauslaneFan : public fan::Fan, public Component, public HauslaneChild {
	public:
		void setup() override;
		void dump_config() override;
		fan::FanTraits get_traits() override;
		void set_speed(int speed);
	
	protected:
		void control(const fan::FanCall &call) override;
};
#endif

}
}
