import 'package:change_case/change_case.dart';

import 'utils.dart';

const packageName = "comwell_key_app";

Future<void> main(List<String> args) async {
  // create files
  if (args.isEmpty) throw Exception("Missing args");
  if (args.length > 1) throw Exception("Too many arguments");
  final featureName = args[0];
  final className = featureName.toPascalCase();
  final snakeCase = featureName.toSnakeCase();
  final blocFile = await createFile(
    "lib/presentation/screens/$featureName/bloc/${featureName}_cubit.dart",
  );
  final stateFile = await createFile(
    "lib/presentation/screens/$featureName/bloc/${featureName}_state.dart",
  );
  final screenFile = await createFile(
    "lib/presentation/screens/$featureName/${featureName}_screen.dart",
  );
  final routeFile = await createFile(
    "lib/presentation/screens/$featureName/${featureName}_route.dart",
  );

  // write files
  await writeToFile(screenFile, screenTemplate(snakeCase, className));
  await writeToFile(stateFile, stateTemplate(snakeCase, className));
  await writeToFile(blocFile, blocTemplate(snakeCase, className));
  await writeToFile(routeFile, routeTemplate(snakeCase, className));
  print("$featureName created successfully");
}

String screenTemplate(String snakeCase, String className) {
  final cubitName = "${className}Cubit";
  final screenName = "${className}Screen";
  final stateName = "${className}State";
  return """
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:$packageName/presentation/screens/$snakeCase/bloc/${snakeCase}_cubit.dart';
import 'package:$packageName/presentation/screens/$snakeCase/bloc/${snakeCase}_state.dart';

class $screenName extends StatelessWidget {
  const $screenName({super.key});

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<$cubitName, $stateName>(
      builder: (context, state) {
        final cubit = context.read<$cubitName>();
        return MultiBlocListener(
          listeners: [
            BlocListener<$cubitName, $stateName>(
              listenWhen: (prev, curr) =>
                  prev.isLoading && !curr.isLoading && curr.error.isError,
              listener: (context, state) {
                // context.showErrorSnackBar(state.errorMessage);
              },
            )
          ],
          child: Scaffold(
            appBar: AppBar(),
            body: Center(
              child: Column(
                children: [
                  Text("$className"),
                ],
              ),
            ),
          ),
        );
      },
    );
 }
}
"""
      .trim();
}

String stateTemplate(String snakeCase, String className) {
  final stateName = "${className}State";
  return """
import 'package:comwell_key_app/domain/models/app_error.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part '../../../../.generated/presentation/screens/$snakeCase/bloc/${snakeCase}_state.freezed.dart';

@freezed
abstract class $stateName with _\$$stateName {
  const factory $stateName({
    @Default(false) bool isLoading,
    @Default(AppError.none) AppError error,
  }) = _$stateName;
  
  $stateName loading() => copyWith(isLoading: true, error: AppError.none); 
}

"""
      .trim();
}

String blocTemplate(String snakeCase, String className) {
  final cubitName = "${className}Cubit";
  final stateName = "${className}State";
  return """
import 'package:comwell_key_app/domain/models/app_error.dart';
import 'package:$packageName/presentation/base/base_cubit.dart';
import 'package:$packageName/presentation/screens/$snakeCase/bloc/${snakeCase}_state.dart';

class $cubitName extends BaseCubit<$stateName> {
  $cubitName() : super(const $stateName()) {
    init();
  }

  Future<void> init() async {
    try {
      safeEmit(state.loading());
      // await Function();
    } catch (e, st) {
      logError(e, st);
      safeEmit(state.copyWith(error: AppError.unknown(e.toString())));
    } finally {
      safeEmit(state.copyWith(isLoading: false));
    }
  }
}
  """
      .trim();
}

String routeTemplate(String snakeCase, String className) {
  final routeName = "${className}Route";
  final pathName = "static const ${className.toCamelCase()} = \"/${className.toKebabCase()}\";";
  final cubitName = "${className}Cubit";
  final screenName = "${className}Screen";

  return """
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:$packageName/presentation/navigation/transitions/slide_in_transition.dart';
import 'package:$packageName/presentation/screens/$snakeCase/bloc/${snakeCase}_cubit.dart';
import 'package:$packageName/presentation/screens/$snakeCase/${snakeCase}_screen.dart';

part '../../../.generated/presentation/screens/$snakeCase/${snakeCase}_route.g.dart';

@TypedGoRoute<$routeName>(
  path: "/${className.toKebabCase()}", // add me to AppRoutes: $pathName
)
class $routeName extends GoRouteData with \$$routeName {

  @override
  Page<void> buildPage(BuildContext context, GoRouterState state) {
    return SlideInTransition(
      state: state,
      child: BlocProvider(
        create: (context) => $cubitName(),
        child: const $screenName(),
      ),
    );
  }
}"""
      .trim();
}