#include <AppKit/AppKit.h>
#include "CGameOptionsTouchBar.hpp"
#include "CGameOptions.hpp"
#include "GameGlobalObjects.hpp"
#include "MP1/MP1.hpp"
#include "GuiSys/CStringTable.hpp"

#if !__has_feature(objc_arc)
#error ARC Required
#endif

static NSColor* BlueConfirm()
{
    return [NSColor colorWithSRGBRed:0/255.f green:130/255.f blue:215/255.f alpha:1.f];
}

@interface GameOptionsTouchBar : NSObject <NSTouchBarDelegate>
{
@public
    metaforce::CStringTable* _pauseScreenStrg;
    metaforce::CGameOptionsTouchBar::EAction _action;
    std::pair<int, int> _selection;
    int _value, _pendingValue;
}
-(IBAction)onBack:(id)sender;
-(IBAction)onSlide:(id)sender;
-(IBAction)onSet0:(id)sender;
-(IBAction)onSet1:(id)sender;
-(IBAction)onSet2:(id)sender;
-(IBAction)onLeft:(id)sender;
-(IBAction)onRight:(id)sender;
@end

@implementation GameOptionsTouchBar
- (NSTouchBar*)makeTouchBar
{
    NSTouchBar* touchBar = [NSTouchBar new];
    touchBar.delegate = self;
    id items = @[@"optionsGroup"];
    touchBar.customizationRequiredItemIdentifiers = items;
    touchBar.defaultItemIdentifiers = items;
    touchBar.principalItemIdentifier = @"optionsGroup";
    return touchBar;
}
-(NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar
     makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier
{
    if ([identifier isEqualToString:@"optionsGroup"])
    {
        NSGroupTouchBarItem* item = [[NSGroupTouchBarItem alloc] initWithIdentifier:identifier];
        NSTouchBar* touchBar = [NSTouchBar new];
        touchBar.delegate = self;
        id items;
        if (_selection.first == -1)
        {
            items = [NSMutableArray arrayWithCapacity:5];
            [items addObject:@"back"];
            for (int i=0 ; i<4 ; ++i)
                [items addObject:[NSString stringWithFormat:@"left/%d", i]];
        }
        else if (_selection.second == -1)
        {
            const std::pair<int, const metaforce::SGameOption*>& opt = metaforce::GameOptionsRegistry[_selection.first];
            items = [NSMutableArray arrayWithCapacity:opt.first+1];
            [items addObject:@"back"];
            for (int i=0 ; i<opt.first ; ++i)
                [items addObject:[NSString stringWithFormat:@"right/%d", i]];
        }
        else
        {
            const std::pair<int, const metaforce::SGameOption*>& opt = metaforce::GameOptionsRegistry[_selection.first];
            const metaforce::SGameOption& subopt = opt.second[_selection.second];
            if (subopt.type == metaforce::EOptionType::Float)
                items = @[@"back", @"value"];
            else if (subopt.type == metaforce::EOptionType::DoubleEnum)
                items = @[@"back", @"label", @"double0", @"double1"];
            else if (subopt.type == metaforce::EOptionType::TripleEnum)
                items = @[@"back", @"label", @"triple0", @"triple1", @"triple2"];
        }
        touchBar.customizationRequiredItemIdentifiers = items;
        touchBar.defaultItemIdentifiers = items;
        item.groupTouchBar = touchBar;
        return item;
    }
    else if ([identifier isEqualToString:@"back"])
    {
        NSCustomTouchBarItem* item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
        NSButton* button = [NSButton buttonWithImage:[NSImage imageNamed:NSImageNameTouchBarGoBackTemplate]
                                              target:self action:@selector(onBack:)];
        item.view = button;
        return item;
    }
    else if ([identifier isEqualToString:@"label"])
    {
        const std::pair<int, const metaforce::SGameOption*>& opt = metaforce::GameOptionsRegistry[_selection.first];
        const metaforce::SGameOption& subopt = opt.second[_selection.second];

        const char16_t* cStr = _pauseScreenStrg->GetString(subopt.stringId);
        NSString* str = [NSString stringWithUTF8String:hecl::Char16ToUTF8(cStr).c_str()];

        NSCustomTouchBarItem* item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
        NSTextField* label = [NSTextField labelWithString:[str stringByAppendingString:@":"]];
        item.view = label;
        return item;
    }
    else if ([identifier isEqualToString:@"value"])
    {
        const std::pair<int, const metaforce::SGameOption*>& opt = metaforce::GameOptionsRegistry[_selection.first];
        const metaforce::SGameOption& subopt = opt.second[_selection.second];

        const char16_t* cStr = _pauseScreenStrg->GetString(subopt.stringId);
        NSString* str = [NSString stringWithUTF8String:hecl::Char16ToUTF8(cStr).c_str()];

        NSSliderTouchBarItem* item = [[NSSliderTouchBarItem alloc] initWithIdentifier:identifier];
        NSSlider* slider = [NSSlider sliderWithValue:_value minValue:subopt.minVal maxValue:subopt.maxVal
                                              target:nil action:nil];
        item.target = self;
        item.action = @selector(onSlide:);
        item.slider = slider;
        item.label = str;
        return item;
    }
    else if ([identifier isEqualToString:@"double0"])
    {
        const char16_t* cStr = _pauseScreenStrg->GetString(95); // Off
        NSString* str = [NSString stringWithUTF8String:hecl::Char16ToUTF8(cStr).c_str()];

        NSCustomTouchBarItem* item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
        NSButton* button = [NSButton buttonWithTitle:str target:self action:@selector(onSet0:)];
        if (_value == 0)
            button.bezelColor = BlueConfirm();
        item.view = button;
        return item;
    }
    else if ([identifier isEqualToString:@"double1"])
    {
        const char16_t* cStr = _pauseScreenStrg->GetString(94); // On
        NSString* str = [NSString stringWithUTF8String:hecl::Char16ToUTF8(cStr).c_str()];

        NSCustomTouchBarItem* item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
        NSButton* button = [NSButton buttonWithTitle:str target:self action:@selector(onSet1:)];
        if (_value == 1)
            button.bezelColor = BlueConfirm();
        item.view = button;
        return item;
    }
    else if ([identifier isEqualToString:@"triple0"])
    {
        const char16_t* cStr = _pauseScreenStrg->GetString(96); // Mono
        NSString* str = [NSString stringWithUTF8String:hecl::Char16ToUTF8(cStr).c_str()];

        NSCustomTouchBarItem* item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
        NSButton* button = [NSButton buttonWithTitle:str target:self action:@selector(onSet0:)];
        if (_value == 0)
            button.bezelColor = BlueConfirm();
        item.view = button;
        return item;
    }
    else if ([identifier isEqualToString:@"triple1"])
    {
        const char16_t* cStr = _pauseScreenStrg->GetString(97); // Stereo
        NSString* str = [NSString stringWithUTF8String:hecl::Char16ToUTF8(cStr).c_str()];

        NSCustomTouchBarItem* item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
        NSButton* button = [NSButton buttonWithTitle:str target:self action:@selector(onSet1:)];
        if (_value == 1)
            button.bezelColor = BlueConfirm();
        item.view = button;
        return item;
    }
    else if ([identifier isEqualToString:@"triple2"])
    {
        const char16_t* cStr = _pauseScreenStrg->GetString(98); // Dolby
        NSString* str = [NSString stringWithUTF8String:hecl::Char16ToUTF8(cStr).c_str()];

        NSCustomTouchBarItem* item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
        NSButton* button = [NSButton buttonWithTitle:str target:self action:@selector(onSet2:)];
        if (_value == 2)
            button.bezelColor = BlueConfirm();
        item.view = button;
        return item;
    }
    else
    {
        NSArray<NSString*>* pc = [identifier pathComponents];
        if ([pc count] == 2)
        {
            NSString* first = [pc objectAtIndex:0];
            if ([first isEqualToString:@"left"])
            {
                auto idx = strtoul([[pc objectAtIndex:1] UTF8String], nullptr, 10);
                const char16_t* cStr = _pauseScreenStrg->GetString(16+idx);
                NSString* str = [NSString stringWithUTF8String:hecl::Char16ToUTF8(cStr).c_str()];

                NSCustomTouchBarItem* item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
                NSButton* button = [NSButton buttonWithTitle:str target:self action:@selector(onLeft:)];
                button.tag = idx;
                item.view = button;
                return item;
            }
            else if ([first isEqualToString:@"right"])
            {
                const std::pair<int, const metaforce::SGameOption*>& opt = metaforce::GameOptionsRegistry[_selection.first];
                auto idx = strtoul([[pc objectAtIndex:1] UTF8String], nullptr, 10);
                const metaforce::SGameOption& subopt = opt.second[idx];
                const char16_t* cStr = _pauseScreenStrg->GetString(subopt.stringId);
                NSString* str = [NSString stringWithUTF8String:hecl::Char16ToUTF8(cStr).c_str()];

                NSCustomTouchBarItem* item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
                NSButton* button = [NSButton buttonWithTitle:str target:self action:@selector(onRight:)];
                button.tag = idx;
                item.view = button;
                return item;
            }
        }
    }
    return nil;
}
-(IBAction)onBack:(id)sender
{
    _action = metaforce::CGameOptionsTouchBar::EAction::Back;
}
-(IBAction)onSlide:(id)sender
{
    _pendingValue = [((NSSliderTouchBarItem*)sender).slider intValue];
    _action = metaforce::CGameOptionsTouchBar::EAction::ValueChange;
}
-(IBAction)onSet0:(id)sender
{
    _pendingValue = 0;
    _action = metaforce::CGameOptionsTouchBar::EAction::ValueChange;
}
-(IBAction)onSet1:(id)sender
{
    _pendingValue = 1;
    _action = metaforce::CGameOptionsTouchBar::EAction::ValueChange;
}
-(IBAction)onSet2:(id)sender
{
    _pendingValue = 2;
    _action = metaforce::CGameOptionsTouchBar::EAction::ValueChange;
}
-(IBAction)onLeft:(id)sender
{
    _selection.first = ((NSButton*)sender).tag;
    _action = metaforce::CGameOptionsTouchBar::EAction::Advance;
}
-(IBAction)onRight:(id)sender
{
    _selection.second = ((NSButton*)sender).tag;
    _action = metaforce::CGameOptionsTouchBar::EAction::Advance;
}
@end

namespace metaforce
{

class CGameOptionsTouchBarMac : public CGameOptionsTouchBar
{
    TLockedToken<CStringTable> m_pauseScreen;
    GameOptionsTouchBar* m_touchBar;
    bool m_initialized = false;
public:
    CGameOptionsTouchBarMac()
    {
        m_pauseScreen = g_SimplePool->GetObj("STRG_PauseScreen");
        m_touchBar = [GameOptionsTouchBar new];
        m_touchBar->_pauseScreenStrg = m_pauseScreen.GetObj();
        m_touchBar->_selection = std::make_pair(-1, -1);
        m_touchBar->_value = -1;
    }
    EAction PopAction()
    {
        if (m_touchBar->_action != EAction::None)
        {
            EAction action = m_touchBar->_action;
            m_touchBar->_action = EAction::None;
            return action;
        }
        return EAction::None;
    }
    void GetSelection(int& left, int& right, int& value)
    {
        left = m_touchBar->_selection.first;
        right = m_touchBar->_selection.second;
        value = m_touchBar->_pendingValue;
    }
    void SetSelection(int left, int right, int value)
    {
        if (m_initialized &&
            left == m_touchBar->_selection.first &&
            right == m_touchBar->_selection.second &&
            value == m_touchBar->_value)
            return;
        m_initialized = true;
        m_touchBar->_selection = std::make_pair(left, right);
        m_touchBar->_value = value;
        g_Main->GetMainWindow()->setTouchBarProvider((__bridge_retained void*)m_touchBar);
    }
};

std::unique_ptr<CGameOptionsTouchBar> NewGameOptionsTouchBar()
{
    return std::make_unique<CGameOptionsTouchBarMac>();
}

}
