import 'package:collection/collection.dart';

import 'package:pshared/api/requests/login_data.dart';
import 'package:pshared/models/account/account.dart';
import 'package:pshared/models/describable.dart';
import 'package:pshared/models/storable.dart';

import 'mock_ids.dart';

class InvalidCredentialsException implements Exception {
  @override
  String toString() => 'InvalidCredentialsException';
}

class DuplicateAccountException implements Exception {
  @override
  String toString() => 'DuplicateAccountException';
}

class AccountLoginResult {
  final Account account;
  final String roleId;

  const AccountLoginResult({
    required this.account,
    required this.roleId,
  });
}

class _AccountRecord {
  final Account account;
  final String password;
  final String roleId;

  const _AccountRecord({
    required this.account,
    required this.password,
    required this.roleId,
  });
}

class AccountsService {
  final List<_AccountRecord> _accounts = [
    _AccountRecord(
      account: Account(
        storable: newStorable(id: companyAccountRef),
        describable: newDescribable(name: 'Sendico Company'),
        avatarUrl: null,
        lastName: 'Owner',
        login: 'company@sendico.com',
        locale: 'ru',
      ),
      password: 'password123A',
      roleId: companyRoleId,
    ),
    _AccountRecord(
      account: Account(
        storable: newStorable(id: recipientAccountRef),
        describable: newDescribable(name: 'John Recipient'),
        avatarUrl: null,
        lastName: 'Doe',
        login: 'recipient@sendico.com',
        locale: 'ru',
      ),
      password: 'password123A',
      roleId: recipientRoleId,
    ),
  ];

  Future<AccountLoginResult> login(String email, String password, {String? locale}) async {
    await Future.delayed(const Duration(milliseconds: 300));

    final normalized = email.trim().toLowerCase();
    final record = _accounts.where((acc) => acc.account.login.toLowerCase() == normalized).singleOrNull;

    if (record == null || record.password != password) {
      throw InvalidCredentialsException();
    }

    return AccountLoginResult(account: record.account, roleId: record.roleId);
  }

  Future<AccountLoginResult> signup(AccountData data, {String roleId = recipientRoleId}) async {
    await Future.delayed(const Duration(milliseconds: 300));

    final normalized = data.login.trim().toLowerCase();
    if (_accounts.any((acc) => acc.account.login.toLowerCase() == normalized)) {
      throw DuplicateAccountException();
    }

    final account = Account(
      storable: newStorable(id: 'account-${_accounts.length + 1}'),
      describable: newDescribable(name: data.name),
      avatarUrl: null,
      lastName: data.lastName,
      login: normalized,
      locale: data.locale,
    );

    _accounts.add(_AccountRecord(account: account, password: data.password, roleId: roleId));
    return AccountLoginResult(account: account, roleId: roleId);
  }

  Account? getByRef(String accountRef) => _accounts.where((acc) => acc.account.id == accountRef).singleOrNull?.account;
}
