<?php

declare(strict_types=1);

namespace PhpOffice\PhpSpreadsheetTests\Shared;

use DateTime;
use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Csv;
use PHPUnit\Framework\TestCase;

class StringHelperTest extends TestCase
{
    protected function tearDown(): void
    {
        StringHelper::setLocale(null);
    }

    public function testGetIsIconvEnabled(): void
    {
        $result = StringHelper::getIsIconvEnabled();
        self::assertTrue($result);
    }

    public function testGetDecimalSeparator(): void
    {
        $localeconv = localeconv();

        $expectedResult = (!empty($localeconv['decimal_point'])) ? $localeconv['decimal_point'] : ',';
        $result = StringHelper::getDecimalSeparator();
        self::assertEquals($expectedResult, $result);
    }

    public function testSetDecimalSeparator(): void
    {
        $expectedResult = ',';
        StringHelper::setDecimalSeparator($expectedResult);

        $result = StringHelper::getDecimalSeparator();
        self::assertEquals($expectedResult, $result);
    }

    public function testGetThousandsSeparator(): void
    {
        $localeconv = localeconv();

        $expectedResult = (!empty($localeconv['thousands_sep'])) ? $localeconv['thousands_sep'] : ',';
        $result = StringHelper::getThousandsSeparator();
        self::assertEquals($expectedResult, $result);
    }

    public function testSetThousandsSeparator(): void
    {
        $expectedResult = ' ';
        StringHelper::setThousandsSeparator($expectedResult);

        $result = StringHelper::getThousandsSeparator();
        self::assertEquals($expectedResult, $result);
    }

    public function testGetCurrencyCode(): void
    {
        $localeconv = localeconv();
        $expectedResult = (!empty($localeconv['currency_symbol']) ? $localeconv['currency_symbol'] : (!empty($localeconv['int_curr_symbol']) ? $localeconv['int_curr_symbol'] : '$'));
        $result = StringHelper::getCurrencyCode();
        self::assertEquals($expectedResult, $result);
    }

    public function testSetCurrencyCode(): void
    {
        $expectedResult = '£';
        StringHelper::setCurrencyCode($expectedResult);

        $result = StringHelper::getCurrencyCode();
        self::assertEquals($expectedResult, $result);
    }

    public function testControlCharacterPHP2OOXML(): void
    {
        $expectedResult = 'foo_x000B_bar';
        $result = StringHelper::controlCharacterPHP2OOXML('foo' . chr(11) . 'bar');

        self::assertEquals($expectedResult, $result);
    }

    public function testControlCharacterOOXML2PHP(): void
    {
        $expectedResult = 'foo' . chr(11) . 'bar';
        $result = StringHelper::controlCharacterOOXML2PHP('foo_x000B_bar');

        self::assertEquals($expectedResult, $result);
    }

    public function testSYLKtoUTF8(): void
    {
        $expectedResult = 'foo' . chr(11) . 'bar';
        $result = StringHelper::SYLKtoUTF8("foo\x1B ;bar");

        self::assertEquals($expectedResult, $result);
    }

    public function testIssue3900(): void
    {
        StringHelper::setDecimalSeparator('.');
        StringHelper::setThousandsSeparator('');

        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();
        $sheet->setCellValue('A1', 1.4);
        $sheet->setCellValue('B1', 1004.5);
        $sheet->setCellValue('C1', 1000000.5);

        ob_start();
        $ioWriter = new Csv($spreadsheet);
        $ioWriter->setDelimiter(';');
        $ioWriter->save('php://output');
        $output = ob_get_clean();
        $spreadsheet->disconnectWorksheets();
        self::assertSame('"1.4";"1004.5";"1000000.5"' . PHP_EOL, $output);
    }

    public function testNonStringable(): void
    {
        $dt = new DateTime();
        self::assertSame('', StringHelper::convertToString($dt, false));
        $this->expectException(SpreadsheetException::class);
        $this->expectExceptionMessage('Unable to convert to string');
        StringHelper::convertToString($dt);
    }

    public function testNoIconv(): void
    {
        $string = "\xBF"; // inverted question mark in ISO-8859-1
        $expected = '¿';
        $from = 'ISO-8859-1';
        $to = 'UTF-8';
        self::assertSame($expected, StringHelper::convertEncoding($string, $to, $from));
        self::assertSame('EUR', StringHelper::convertEncoding('€', 'ISO-8859-1', 'UTF-8'), 'transliterated');
        self::assertSame($expected, StringHelperNoIconv::convertEncoding($string, $to, $from));
        self::assertSame('?', StringHelperNoIconv::convertEncoding('€', 'ISO-8859-1', 'UTF-8'), 'using MB so no transliteration - just return question mark');
        self::assertSame($expected, StringHelperNoIconv2::convertEncoding($string, $to, $from));
        self::assertSame('?', StringHelperNoIconv2::convertEncoding('€', 'ISO-8859-1', 'UTF-8'), 'using MB so no transliteration - just return question mark');
        self::assertSame($expected, StringHelperNoIconv3::convertEncoding($string, $to, $from));
        self::assertSame('?', StringHelperNoIconv3::convertEncoding('€', 'ISO-8859-1', 'UTF-8'), 'using MB so no transliteration - just return question mark');

        $noTransliteration = 'ﾂ';
        // There is inconsistency in how //TRANSLIT operates.
        // On some systems, '?' seems to be used if there is
        // no other transliteration available.
        $ignoreResult = '?';
        if (StringHelper::getIsIconvEnabled()) {
            $ignoreResult = iconv('UTF-8', 'ISO-8859-1//IGNORE//TRANSLIT', $noTransliteration);
            self::assertContains($ignoreResult, ['', '?']);
        }
        self::assertSame($ignoreResult, StringHelper::convertEncoding($noTransliteration, 'ISO-8859-1', 'UTF-8'), 'no transliteration available');
        self::assertSame('', StringHelper::convertEncoding($noTransliteration, 'ISO-8859-1', 'UTF-8', '//IGNORE'), 'TRANSLIT not used');
    }
}
