/*
 * Copyright 2022 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "modules/skottie/utils/TextEditor.h"

#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkM44.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathBuilder.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSpan.h"
#include "include/core/SkString.h"
#include "src/core/SkUTF.h"
#include "tools/skui/InputState.h"

#include <algorithm>
#include <limits>
#include <utility>

namespace skottie_utils {

namespace {

SkPath make_cursor_path() {
    // Normalized values, relative to text/font size.
    constexpr float kWidth  = 0.2f,
                    kHeight = 0.75f;

    SkPathBuilder p;

    p.moveTo(0, 0);
    p.lineTo(kWidth  , 0);
    p.moveTo(kWidth/2, 0);
    p.lineTo(kWidth/2, kHeight);
    p.moveTo(0       , kHeight);
    p.lineTo(kWidth  , kHeight);

    return p.detach();
}

size_t next_utf8(const SkString& str, size_t index) {
    SkASSERT(index < str.size());

    const char* utf8_ptr = str.c_str() + index;

    if (SkUTF::NextUTF8(&utf8_ptr, str.c_str() + str.size()) < 0){
        // Invalid UTF sequence.
        return index;
    }

    return utf8_ptr - str.c_str();
}

size_t prev_utf8(const SkString& str, size_t index) {
    SkASSERT(index > 0);

    // Find the previous utf8 index by probing the preceding 4 offsets.  Utf8 leading bytes are
    // always distinct from continuation bytes, so only one of these probes will succeed.
    for (unsigned i = 1; i <= SkUTF::kMaxBytesInUTF8Sequence && i <= index; ++i) {
        const char* utf8_ptr = str.c_str() + index - i;
        if (SkUTF::NextUTF8(&utf8_ptr, str.c_str() + str.size()) >= 0) {
            return index - i;
        }
    }

    // Invalid UTF sequence.
    return index;
}

} // namespace

TextEditor::TextEditor(
        std::unique_ptr<skottie::TextPropertyHandle>&& prop,
        std::vector<std::unique_ptr<skottie::TextPropertyHandle>>&& deps)
    : fTextProp(std::move(prop))
    , fDependentProps(std::move(deps))
    , fCursorPath(make_cursor_path())
    , fCursorBounds(fCursorPath.computeTightBounds())
{}

TextEditor::~TextEditor() = default;

void TextEditor::toggleEnabled() {
    fEnabled = !fEnabled;

    auto txt = fTextProp->get();
    txt.fDecorator = fEnabled ? sk_ref_sp(this) : nullptr;
    fTextProp->set(txt);

    if (fEnabled) {
        // Always reset the cursor position to the end.
        fCursorIndex = txt.fText.size();
    }

    fTimeBase = std::chrono::steady_clock::now();
}

void TextEditor::setEnabled(bool enabled) {
    if (enabled != fEnabled) {
        this->toggleEnabled();
    }
}

std::tuple<size_t, size_t> TextEditor::currentSelection() const {
    // Selection can be inverted.
    return std::make_tuple(std::min(std::get<0>(fSelection), std::get<1>(fSelection)),
                           std::max(std::get<0>(fSelection), std::get<1>(fSelection)));
}

size_t TextEditor::closestGlyph(const SkPoint& pt) const {
    float  min_distance = std::numeric_limits<float>::max();
    size_t min_index    = 0;

    for (size_t i = 0; i < fGlyphData.size(); ++i) {
        const auto dist = (fGlyphData[i].fDevBounds.center() - pt).length();
        if (dist < min_distance) {
            min_distance = dist;
            min_index = i;
        }
    }

    return min_index;
}

void TextEditor::drawCursor(SkCanvas* canvas, const TextInfo& tinfo) const {
    constexpr double kCursorHz = 2;
    const auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                            std::chrono::steady_clock::now() - fTimeBase).count();
    const long cycle = static_cast<long>(static_cast<double>(now_ms) * 0.001 * kCursorHz);
    if (cycle & 1) {
        // blink
        return;
    }

    auto txt_prop  = fTextProp->get();

    const auto glyph_index = [&]() -> size_t {
        if (!fCursorIndex) {
            return 0;
        }

        const auto prev_index = prev_utf8(txt_prop.fText, fCursorIndex);
        for (size_t i = 0; i < tinfo.fGlyphs.size(); ++i) {
            if (tinfo.fGlyphs[i].fCluster >= prev_index) {
                return i;
            }
        }

        return tinfo.fGlyphs.size() - 1;
    }();

    // Cursor index mapping:
    //   0 -> before the first char
    //   1 -> after the first char
    //   2 -> after the second char
    //   ...
    // The cursor is bottom-aligned to the baseline (y = 0), and horizontally centered to the right
    // of the glyph advance.
    const auto cscale = txt_prop.fTextSize * tinfo.fScale,
                cxpos = (fCursorIndex ? tinfo.fGlyphs[glyph_index].fAdvance : 0)
                         - fCursorBounds.width() * cscale * 0.5f,
                cypos = - fCursorBounds.height() * cscale;
    const auto cpath  = fCursorPath.makeTransform(SkMatrix::Translate(cxpos, cypos) *
                                                  SkMatrix::Scale(cscale, cscale));

    // We stroke the cursor twice, with different colors, to ensure reasonable contrast
    // regardless of background.
    // The default inner stroke width is .5px for a font size of 10, and scales proportionally.
    // The outer stroke width is slightly larger.
    const auto inner_width = cscale * fCursorWeight * 0.05f,
               outer_width = inner_width * 3 / 2;

    SkPaint p;
    p.setAntiAlias(true);
    p.setStyle(SkPaint::kStroke_Style);
    p.setStrokeCap(SkPaint::kRound_Cap);

    SkAutoCanvasRestore acr(canvas, true);
    canvas->concat(tinfo.fGlyphs[glyph_index].fMatrix);

    p.setColor(SK_ColorWHITE);
    p.setStrokeWidth(outer_width);
    canvas->drawPath(cpath, p);
    p.setColor(SK_ColorBLACK);
    p.setStrokeWidth(inner_width);
    canvas->drawPath(cpath, p);
}

void TextEditor::updateDeps(const SkString& txt) {
    for (const auto& dep : fDependentProps) {
        auto txt_prop = dep->get();
        txt_prop.fText = txt;
        dep->set(txt_prop);
    }
}

void TextEditor::insertChar(SkUnichar c) {
    auto txt = fTextProp->get();
    const auto initial_size = txt.fText.size();

    txt.fText.insertUnichar(fCursorIndex, c);
    fCursorIndex += txt.fText.size() - initial_size;

    fTextProp->set(txt);
    this->updateDeps(txt.fText);
}

void TextEditor::deleteChars(size_t offset, size_t count) {
    auto txt = fTextProp->get();

    txt.fText.remove(offset, count);
    fTextProp->set(txt);
    this->updateDeps(txt.fText);

    fCursorIndex = offset;
}

bool TextEditor::deleteSelection() {
    const auto [glyph_sel_start, glyph_sel_end] = this->currentSelection();
    if (glyph_sel_start == glyph_sel_end) {
        return false;
    }

    const auto utf8_sel_start = fGlyphData[glyph_sel_start].fCluster,
               utf8_sel_end   = fGlyphData[glyph_sel_end  ].fCluster;
    SkASSERT(utf8_sel_start < utf8_sel_end);

    this->deleteChars(utf8_sel_start, utf8_sel_end - utf8_sel_start);

    fSelection = {0,0};

    return true;
}

void TextEditor::onDecorate(SkCanvas* canvas, const TextInfo& tinfo) {
    const auto [sel_start, sel_end] = this->currentSelection();

    fGlyphData.clear();

    for (size_t i = 0; i < tinfo.fGlyphs.size(); ++i) {
        const auto& ginfo = tinfo.fGlyphs[i];

        SkAutoCanvasRestore acr(canvas, true);
        canvas->concat(ginfo.fMatrix);

        // Stash some glyph info, for later use.
        fGlyphData.push_back({
            canvas->getLocalToDevice().asM33().mapRect(ginfo.fBounds),
            ginfo.fCluster
        });

        if (i < sel_start || i >= sel_end) {
            continue;
        }

        static constexpr SkColor4f kSelectionColor{0, 0, 1, 0.4f};
        canvas->drawRect(ginfo.fBounds, SkPaint(kSelectionColor));
    }

    // Only draw the cursor when there's no active selection.
    if (sel_start == sel_end) {
        this->drawCursor(canvas, tinfo);
    }
}

bool TextEditor::onMouseInput(SkScalar x, SkScalar y, skui::InputState state,
                                     skui::ModifierKey) {
    if (!fEnabled || fGlyphData.empty()) {
        return false;
    }

    switch (state) {
    case skui::InputState::kDown: {
        fMouseDown = true;

        const auto closest = this->closestGlyph({x, y});
        fSelection = {closest, closest};
    }   break;
    case skui::InputState::kUp:
        fMouseDown = false;
        break;
    case skui::InputState::kMove:
        if (fMouseDown) {
            const auto closest = this->closestGlyph({x, y});
            std::get<1>(fSelection) = closest < std::get<0>(fSelection)
                                            ? closest
                                            : closest + 1;
        }
        break;
    default:
        break;
    }

    return true;
}

bool TextEditor::onCharInput(SkUnichar c) {
    if (!fEnabled || fGlyphData.empty()) {
        return false;
    }

    const auto& txt_str = fTextProp->get().fText;

    // Natural editor bindings are currently intercepted by Viewer, so we use these instead.
    switch (c) {
    case '|':     // commit changes and exit editing mode
        this->toggleEnabled();
        break;
    case ']': {   // move right
        if (fCursorIndex < txt_str.size()) {
            fCursorIndex = next_utf8(txt_str, fCursorIndex);
        }
    } break;
    case '[':     // move left
        if (fCursorIndex > 0) {
            fCursorIndex = prev_utf8(txt_str, fCursorIndex);
        }
        break;
    case '\\': {  // delete
        if (!this->deleteSelection() && fCursorIndex > 0) {
            // Delete preceding char.
            const auto del_index = prev_utf8(txt_str, fCursorIndex),
                       del_count = fCursorIndex - del_index;

            this->deleteChars(del_index, del_count);
        }
    }   break;
    default:
        // Delete any selection on insert.
        this->deleteSelection();
        this->insertChar(c);
        break;
    }

    // Reset the cursor blink timer on input.
    fTimeBase = std::chrono::steady_clock::now();

    return true;
}

}  // namespace skottie_utils
