This is an interesting problem. I'm sure there are already algorithms out there, but I'm going to take a shot in the dark.
Taking cover is only applicable from the player's point of view. So when triggered, I would cast line of sight rays from the player towards the enemy, starting from a direct line, and then gradually getting wider to the sides. When an obstacle in range is hit, create helper "movement targets" along the path of the ray away from the player starting from the intersection point, deleting ones that overlap, until the first free space is "hit". That will give you a bunch (or just 2, or only first valid one, really up to you how long to search) of valid points that are behind cover from the player. Then we'll want to pick the one to path find to, either the closest one to the player, closest to the center line, closest to the enemy, ect. We can add additional conditions to invalidate movement targets, like too close to the enemy, too high pathfinding cost, ect.
Upon reaching cover, I'd imagine the enemy would need to pop out to get los to shoot, which would simply be pathfinding to the player location until line of sight is acquired, stop, and shoot.
Flanking is similar, except target the rays to the side of the player instead. Build a list of potential movement targets, and use the one that makes most sense, probably the closest one to the enemy unit. You can use additional invisible helper sprites on either side of the player to check for valid "flanking spots", if the movement target overlaps these helper sprites, then it is a valid target. Otherwise, not.