"use strict";

module.exports = {
  meta: {
    type: "problem",
    docs: {
      description:
        "Ensure recoil value and setter are named after their atom name",
      category: "Possible Errors",
      recommended: true,
    },
    fixable: "code",
    schema: [],
  },
  create: function (context) {
    return {
      VariableDeclarator(node) {
        if (
          node?.init?.callee?.name &&
          typeof node.init.callee.name === "string" &&
          [
            'useRecoilState',
            'useRecoilFamilyState',
            'useRecoilSelector',
            'useRecoilScopedState',
            'useRecoilScopedFamilyState',
            'useRecoilScopedSelector',
            'useRecoilValue',
          ].includes(node.init.callee.name)
        ) {
          const stateNameBase = node.init.arguments?.[0].name;

          if (!stateNameBase) {
            return;
          }

          let expectedVariableNameBase = stateNameBase.replace(
            /(State|FamilyState|Selector|ScopedState|ScopedFamilyState|ScopedSelector)$/,
            ""
          );

          if (node.id.type === "Identifier") {
            const actualVariableName = node.id.name;
            if (actualVariableName !== expectedVariableNameBase) {
              context.report({
                node,
                message: `Invalid usage of ${node.init.callee.name}: the value should be named '${expectedVariableNameBase}' but found '${actualVariableName}'.`,
                fix(fixer) {
                  return fixer.replaceText(node.id, expectedVariableNameBase);
                },
              });
            }
            return;
          }

          if (node.id.type === "ArrayPattern") {
            const actualVariableName = node.id.elements?.[0]?.name;

            if (
              actualVariableName &&
              actualVariableName !== expectedVariableNameBase
            ) {
              context.report({
                node,
                message: `Invalid usage of ${node.init.callee.name}: the value should be named '${expectedVariableNameBase}' but found '${actualVariableName}'.`,
                fix(fixer) {
                  return fixer.replaceText(
                    node.id.elements[0],
                    expectedVariableNameBase
                  );
                },
              });
              return;
            }

            if (node.id.elements?.[1]?.name) {
              const actualSetterName = node.id.elements[1].name;
              const expectedSetterName = `set${expectedVariableNameBase
                .charAt(0)
                .toUpperCase()}${expectedVariableNameBase.slice(1)}`;

              if (actualSetterName !== expectedSetterName) {
                context.report({
                  node,
                  message: `Invalid usage of ${node.init.callee.name}: Expected setter '${expectedSetterName}' but found '${actualSetterName}'.`,
                  fix(fixer) {
                    return fixer.replaceText(
                      node.id.elements[1],
                      expectedSetterName
                    );
                  },
                });
              }
            }
          }
        }
      },
    };
  },
};
