// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/painting.dart';
import 'package:flutter_test/flutter_test.dart';

const Rect canvasRect = Rect.fromLTWH(0, 0, 100, 100);
const BorderSide borderSide = BorderSide(width: 4, color: Color(0x0f00ff00));

// Test points for rectangular filled paths based on a BorderSide with width 4 and
// a 100x100 bounding rectangle (canvasRect).
List<Offset> rectIncludes(Rect r) {
  return <Offset>[r.topLeft, r.topRight, r.bottomLeft, r.bottomRight, r.center];
}
final List<Offset> leftRectIncludes = rectIncludes(const Rect.fromLTWH(0, 0, 4, 100));
final List<Offset> rightRectIncludes = rectIncludes(const Rect.fromLTWH(96, 0, 4, 100));
final List<Offset> topRectIncludes = rectIncludes(const Rect.fromLTWH(0, 0, 100, 4));
final List<Offset> bottomRectIncludes = rectIncludes(const Rect.fromLTWH(0, 96, 100, 4));


void main() {
  test('LinearBorderEdge defaults', () {
    expect(const LinearBorderEdge().size, 1);
    expect(const LinearBorderEdge().alignment, 0);
  });

  test('LinearBorder defaults', () {
    void expectEmptyBorder(LinearBorder border) {
      expect(border.side, BorderSide.none);
      expect(border.dimensions, EdgeInsets.zero);
      expect(border.preferPaintInterior, false);
      expect(border.start, null);
      expect(border.end, null);
      expect(border.top, null);
      expect(border.bottom, null);
    }
    expectEmptyBorder(LinearBorder.none);

    expect(LinearBorder.start().side, BorderSide.none);
    expect(LinearBorder.start().start, const LinearBorderEdge());
    expect(LinearBorder.start().end, null);
    expect(LinearBorder.start().top, null);
    expect(LinearBorder.start().bottom, null);

    expect(LinearBorder.end().side, BorderSide.none);
    expect(LinearBorder.end().start, null);
    expect(LinearBorder.end().end, const LinearBorderEdge());
    expect(LinearBorder.end().top, null);
    expect(LinearBorder.end().bottom, null);

    expect(LinearBorder.top().side, BorderSide.none);
    expect(LinearBorder.top().start, null);
    expect(LinearBorder.top().end, null);
    expect(LinearBorder.top().top, const LinearBorderEdge());
    expect(LinearBorder.top().bottom, null);

    expect(LinearBorder.bottom().side, BorderSide.none);
    expect(LinearBorder.bottom().start, null);
    expect(LinearBorder.bottom().end, null);
    expect(LinearBorder.bottom().top, null);
    expect(LinearBorder.bottom().bottom, const LinearBorderEdge());
  });

  test('LinearBorder copyWith, ==, hashCode', () {
    expect(LinearBorder.none, LinearBorder.none.copyWith());
    expect(LinearBorder.none.hashCode, LinearBorder.none.copyWith().hashCode);
    const BorderSide side = BorderSide(width: 10.0, color: Color(0xff123456));
    expect(LinearBorder.none.copyWith(side: side), const LinearBorder(side: side));
  });

  test('LinearBorder lerp identical a,b', () {
    expect(OutlinedBorder.lerp(null, null, 0), null);
    const LinearBorder border = LinearBorder.none;
    expect(identical(OutlinedBorder.lerp(border, border, 0.5), border), true);
  });

  test('LinearBorderEdge.lerp identical a,b', () {
    expect(LinearBorderEdge.lerp(null, null, 0), null);
    const LinearBorderEdge edge = LinearBorderEdge();
    expect(identical(LinearBorderEdge.lerp(edge, edge, 0.5), edge), true);
  });

  test('LinearBorderEdge, LinearBorder toString()', () {
    expect(const LinearBorderEdge(size: 0.5, alignment: -0.5).toString(), 'LinearBorderEdge(size: 0.5, alignment: -0.5)');
    expect(LinearBorder.none.toString(), 'LinearBorder.none');
    const BorderSide side = BorderSide(width: 10.0, color: Color(0xff123456));
    expect(const LinearBorder(side: side).toString(), 'LinearBorder(side: BorderSide(color: Color(0xff123456), width: 10.0))');
    expect(
      const LinearBorder(
        side: side,
        start: LinearBorderEdge(size: 0, alignment: -0.75),
        end: LinearBorderEdge(size: 0.25, alignment: -0.5),
        top: LinearBorderEdge(size: 0.5, alignment: 0.5),
        bottom: LinearBorderEdge(size: 0.75, alignment: 0.75),
      ).toString(),
      'LinearBorder('
        'side: BorderSide(color: Color(0xff123456), width: 10.0), '
        'start: LinearBorderEdge(size: 0.0, alignment: -0.75), '
        'end: LinearBorderEdge(size: 0.25, alignment: -0.5), '
        'top: LinearBorderEdge(size: 0.5, alignment: 0.5), '
        'bottom: LinearBorderEdge(size: 0.75, alignment: 0.75))',
    );
  },
    skip: isBrowser, // [intended] see https://github.com/flutter/flutter/issues/118207
  );

  test('LinearBorder.start()', () {
    final LinearBorder border = LinearBorder.start(side: borderSide);
    expect(
      (Canvas canvas) => border.paint(canvas, canvasRect, textDirection: TextDirection.ltr),
      paints
        ..path(
          includes: leftRectIncludes,
          excludes: rightRectIncludes,
          color: borderSide.color,
        ),
    );
    expect(
      (Canvas canvas) => border.paint(canvas, canvasRect, textDirection: TextDirection.rtl),
      paints
        ..path(
          includes: rightRectIncludes,
          excludes: leftRectIncludes,
          color: borderSide.color,
        ),
    );
  });

  test('LinearBorder.end()', () {
    final LinearBorder border = LinearBorder.end(side: borderSide);
    expect(
      (Canvas canvas) => border.paint(canvas, canvasRect, textDirection: TextDirection.ltr),
      paints
        ..path(
          includes: rightRectIncludes,
          excludes: leftRectIncludes,
          color: borderSide.color,
        ),
    );
    expect(
      (Canvas canvas) => border.paint(canvas, canvasRect, textDirection: TextDirection.rtl),
      paints
        ..path(
          includes: leftRectIncludes,
          excludes: rightRectIncludes,
          color: borderSide.color,
        ),
    );
  });

  test('LinearBorder.top()', () {
    final LinearBorder border = LinearBorder.top(side: borderSide);
    expect(
      (Canvas canvas) => border.paint(canvas, canvasRect, textDirection: TextDirection.ltr),
      paints
        ..path(
          includes: topRectIncludes,
          excludes: bottomRectIncludes,
          color: borderSide.color,
        ),
    );
  });

  test('LinearBorder.bottom()', () {
    final LinearBorder border = LinearBorder.bottom(side: borderSide);
    expect(
      (Canvas canvas) => border.paint(canvas, canvasRect, textDirection: TextDirection.ltr),
      paints
        ..path(
          includes: bottomRectIncludes,
          excludes: topRectIncludes,
          color: borderSide.color,
        ),
    );
  });
}